blob: bc35e216b35ffc8022770d059c1e39c99753ed25 [file] [log] [blame]
Colin Cross3bc7ffa2017-11-22 16:19:37 -08001// Copyright 2017 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
Colin Crossd09b0b62018-04-18 11:06:47 -070018 "fmt"
Colin Crossa4f08812018-10-02 22:03:40 -070019 "path/filepath"
Colin Cross3bc7ffa2017-11-22 16:19:37 -080020 "reflect"
Jaewoong Junga5e5abc2019-04-26 14:31:50 -070021 "regexp"
Colin Crossb69301e2017-12-01 10:48:26 -080022 "sort"
Colin Crossd09b0b62018-04-18 11:06:47 -070023 "strings"
Colin Cross3bc7ffa2017-11-22 16:19:37 -080024 "testing"
Jaewoong Junga5e5abc2019-04-26 14:31:50 -070025
26 "github.com/google/blueprint/proptools"
27
28 "android/soong/android"
29 "android/soong/cc"
Colin Cross3bc7ffa2017-11-22 16:19:37 -080030)
31
32var (
33 resourceFiles = []string{
34 "res/layout/layout.xml",
35 "res/values/strings.xml",
36 "res/values-en-rUS/strings.xml",
37 }
38
39 compiledResourceFiles = []string{
40 "aapt2/res/layout_layout.xml.flat",
41 "aapt2/res/values_strings.arsc.flat",
42 "aapt2/res/values-en-rUS_strings.arsc.flat",
43 }
44)
45
Colin Cross527012a2017-11-30 22:56:16 -080046func testAppContext(config android.Config, bp string, fs map[string][]byte) *android.TestContext {
47 appFS := map[string][]byte{}
48 for k, v := range fs {
49 appFS[k] = v
Colin Cross3bc7ffa2017-11-22 16:19:37 -080050 }
51
Colin Cross527012a2017-11-30 22:56:16 -080052 for _, file := range resourceFiles {
53 appFS[file] = nil
54 }
55
56 return testContext(config, bp, appFS)
57}
58
59func testApp(t *testing.T, bp string) *android.TestContext {
60 config := testConfig(nil)
61
62 ctx := testAppContext(config, bp, nil)
63
64 run(t, ctx, config)
65
66 return ctx
Colin Cross3bc7ffa2017-11-22 16:19:37 -080067}
68
69func TestApp(t *testing.T) {
Colin Crossa97c5d32018-03-28 14:58:31 -070070 for _, moduleType := range []string{"android_app", "android_library"} {
71 t.Run(moduleType, func(t *testing.T) {
72 ctx := testApp(t, moduleType+` {
73 name: "foo",
74 srcs: ["a.java"],
75 }
76 `)
Colin Cross3bc7ffa2017-11-22 16:19:37 -080077
Colin Crossa97c5d32018-03-28 14:58:31 -070078 foo := ctx.ModuleForTests("foo", "android_common")
Colin Cross3bc7ffa2017-11-22 16:19:37 -080079
Colin Cross31656952018-05-24 16:11:20 -070080 var expectedLinkImplicits []string
81
82 manifestFixer := foo.Output("manifest_fixer/AndroidManifest.xml")
83 expectedLinkImplicits = append(expectedLinkImplicits, manifestFixer.Output.String())
Colin Cross3bc7ffa2017-11-22 16:19:37 -080084
Colin Crossa97c5d32018-03-28 14:58:31 -070085 frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
86 expectedLinkImplicits = append(expectedLinkImplicits,
87 frameworkRes.Output("package-res.apk").Output.String())
Colin Cross3bc7ffa2017-11-22 16:19:37 -080088
Colin Crossa97c5d32018-03-28 14:58:31 -070089 // Test the mapping from input files to compiled output file names
90 compile := foo.Output(compiledResourceFiles[0])
91 if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) {
92 t.Errorf("expected aapt2 compile inputs expected:\n %#v\n got:\n %#v",
93 resourceFiles, compile.Inputs.Strings())
94 }
Colin Crossb69301e2017-12-01 10:48:26 -080095
Colin Crossa97c5d32018-03-28 14:58:31 -070096 compiledResourceOutputs := compile.Outputs.Strings()
97 sort.Strings(compiledResourceOutputs)
Colin Crossb69301e2017-12-01 10:48:26 -080098
Colin Crossa97c5d32018-03-28 14:58:31 -070099 expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800100
Colin Crossa97c5d32018-03-28 14:58:31 -0700101 list := foo.Output("aapt2/res.list")
102 expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800103
Colin Crossa97c5d32018-03-28 14:58:31 -0700104 // Check that the link rule uses
105 res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk")
106 if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) {
107 t.Errorf("expected aapt2 link implicits expected:\n %#v\n got:\n %#v",
108 expectedLinkImplicits, res.Implicits.Strings())
109 }
110 })
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800111 }
112}
Colin Cross890ff552017-11-30 20:13:19 -0800113
Colin Crosse560c4a2019-03-19 16:03:11 -0700114func TestAppSplits(t *testing.T) {
115 ctx := testApp(t, `
116 android_app {
117 name: "foo",
118 srcs: ["a.java"],
119 package_splits: ["v4", "v7,hdpi"],
120 }`)
121
122 foo := ctx.ModuleForTests("foo", "android_common")
123
124 expectedOutputs := []string{
125 filepath.Join(buildDir, ".intermediates/foo/android_common/foo.apk"),
126 filepath.Join(buildDir, ".intermediates/foo/android_common/foo_v4.apk"),
127 filepath.Join(buildDir, ".intermediates/foo/android_common/foo_v7_hdpi.apk"),
128 }
129 for _, expectedOutput := range expectedOutputs {
130 foo.Output(expectedOutput)
131 }
132
133 if g, w := foo.Module().(*AndroidApp).Srcs().Strings(), expectedOutputs; !reflect.DeepEqual(g, w) {
134 t.Errorf("want Srcs() = %q, got %q", w, g)
135 }
136}
137
Colin Cross0ddae7f2019-02-07 15:30:01 -0800138func TestResourceDirs(t *testing.T) {
139 testCases := []struct {
140 name string
141 prop string
142 resources []string
143 }{
144 {
145 name: "no resource_dirs",
146 prop: "",
147 resources: []string{"res/res/values/strings.xml"},
148 },
149 {
150 name: "resource_dirs",
151 prop: `resource_dirs: ["res"]`,
152 resources: []string{"res/res/values/strings.xml"},
153 },
154 {
155 name: "empty resource_dirs",
156 prop: `resource_dirs: []`,
157 resources: nil,
158 },
159 }
160
161 fs := map[string][]byte{
162 "res/res/values/strings.xml": nil,
163 }
164
165 bp := `
166 android_app {
167 name: "foo",
168 %s
169 }
170 `
171
172 for _, testCase := range testCases {
173 t.Run(testCase.name, func(t *testing.T) {
174 config := testConfig(nil)
175 ctx := testContext(config, fmt.Sprintf(bp, testCase.prop), fs)
176 run(t, ctx, config)
177
178 module := ctx.ModuleForTests("foo", "android_common")
179 resourceList := module.MaybeOutput("aapt2/res.list")
180
181 var resources []string
182 if resourceList.Rule != nil {
183 for _, compiledResource := range resourceList.Inputs.Strings() {
184 resources = append(resources, module.Output(compiledResource).Inputs.Strings()...)
185 }
186 }
187
188 if !reflect.DeepEqual(resources, testCase.resources) {
189 t.Errorf("expected resource files %q, got %q",
190 testCase.resources, resources)
191 }
192 })
193 }
194}
195
Colin Crossbec85302019-02-13 13:15:46 -0800196func TestAndroidResources(t *testing.T) {
Colin Cross5c4791c2019-02-01 11:44:44 -0800197 testCases := []struct {
198 name string
199 enforceRROTargets []string
200 enforceRROExcludedOverlays []string
Colin Crossbec85302019-02-13 13:15:46 -0800201 resourceFiles map[string][]string
Colin Cross5c4791c2019-02-01 11:44:44 -0800202 overlayFiles map[string][]string
203 rroDirs map[string][]string
204 }{
205 {
206 name: "no RRO",
207 enforceRROTargets: nil,
208 enforceRROExcludedOverlays: nil,
Colin Crossbec85302019-02-13 13:15:46 -0800209 resourceFiles: map[string][]string{
210 "foo": nil,
211 "bar": {"bar/res/res/values/strings.xml"},
212 "lib": nil,
213 "lib2": {"lib2/res/res/values/strings.xml"},
214 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800215 overlayFiles: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800216 "foo": {
217 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800218 buildDir + "/.intermediates/lib/android_common/package-res.apk",
Anton Hansson53c88442019-03-18 15:53:16 +0000219 buildDir + "/.intermediates/lib3/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800220 "foo/res/res/values/strings.xml",
Colin Cross5c4791c2019-02-01 11:44:44 -0800221 "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
222 "device/vendor/blah/overlay/foo/res/values/strings.xml",
Anton Hansson53c88442019-03-18 15:53:16 +0000223 "product/vendor/blah/overlay/foo/res/values/strings.xml",
Colin Cross5c4791c2019-02-01 11:44:44 -0800224 },
Colin Crossbec85302019-02-13 13:15:46 -0800225 "bar": {
Colin Cross5c4791c2019-02-01 11:44:44 -0800226 "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
227 "device/vendor/blah/overlay/bar/res/values/strings.xml",
228 },
Colin Crossbec85302019-02-13 13:15:46 -0800229 "lib": {
230 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
231 "lib/res/res/values/strings.xml",
232 "device/vendor/blah/overlay/lib/res/values/strings.xml",
233 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800234 },
235 rroDirs: map[string][]string{
236 "foo": nil,
237 "bar": nil,
238 },
239 },
240 {
241 name: "enforce RRO on foo",
242 enforceRROTargets: []string{"foo"},
243 enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
Colin Crossbec85302019-02-13 13:15:46 -0800244 resourceFiles: map[string][]string{
245 "foo": nil,
246 "bar": {"bar/res/res/values/strings.xml"},
247 "lib": nil,
248 "lib2": {"lib2/res/res/values/strings.xml"},
249 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800250 overlayFiles: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800251 "foo": {
252 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800253 buildDir + "/.intermediates/lib/android_common/package-res.apk",
Anton Hansson53c88442019-03-18 15:53:16 +0000254 buildDir + "/.intermediates/lib3/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800255 "foo/res/res/values/strings.xml",
256 "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
257 },
Colin Crossbec85302019-02-13 13:15:46 -0800258 "bar": {
Colin Cross5c4791c2019-02-01 11:44:44 -0800259 "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
260 "device/vendor/blah/overlay/bar/res/values/strings.xml",
261 },
Colin Crossbec85302019-02-13 13:15:46 -0800262 "lib": {
263 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
264 "lib/res/res/values/strings.xml",
265 "device/vendor/blah/overlay/lib/res/values/strings.xml",
266 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800267 },
Colin Crossc1c37552019-01-31 11:42:41 -0800268
Colin Cross5c4791c2019-02-01 11:44:44 -0800269 rroDirs: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800270 "foo": {
Anton Hansson53c88442019-03-18 15:53:16 +0000271 "device:device/vendor/blah/overlay/foo/res",
Colin Crossc1c37552019-01-31 11:42:41 -0800272 // Enforce RRO on "foo" could imply RRO on static dependencies, but for now it doesn't.
273 // "device/vendor/blah/overlay/lib/res",
Anton Hansson53c88442019-03-18 15:53:16 +0000274 "product:product/vendor/blah/overlay/foo/res",
Colin Crossc1c37552019-01-31 11:42:41 -0800275 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800276 "bar": nil,
Colin Crossbec85302019-02-13 13:15:46 -0800277 "lib": nil,
Colin Cross5c4791c2019-02-01 11:44:44 -0800278 },
279 },
280 {
281 name: "enforce RRO on all",
282 enforceRROTargets: []string{"*"},
283 enforceRROExcludedOverlays: []string{
284 // Excluding specific apps/res directories also allowed.
285 "device/vendor/blah/static_overlay/foo",
286 "device/vendor/blah/static_overlay/bar/res",
287 },
Colin Crossbec85302019-02-13 13:15:46 -0800288 resourceFiles: map[string][]string{
289 "foo": nil,
290 "bar": {"bar/res/res/values/strings.xml"},
291 "lib": nil,
292 "lib2": {"lib2/res/res/values/strings.xml"},
293 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800294 overlayFiles: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800295 "foo": {
296 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800297 buildDir + "/.intermediates/lib/android_common/package-res.apk",
Anton Hansson53c88442019-03-18 15:53:16 +0000298 buildDir + "/.intermediates/lib3/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800299 "foo/res/res/values/strings.xml",
300 "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
301 },
Colin Crossbec85302019-02-13 13:15:46 -0800302 "bar": {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"},
303 "lib": {
304 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
305 "lib/res/res/values/strings.xml",
306 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800307 },
308 rroDirs: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800309 "foo": {
Anton Hansson53c88442019-03-18 15:53:16 +0000310 "device:device/vendor/blah/overlay/foo/res",
311 "product:product/vendor/blah/overlay/foo/res",
312 // Lib dep comes after the direct deps
313 "device:device/vendor/blah/overlay/lib/res",
Colin Crossc1c37552019-01-31 11:42:41 -0800314 },
Anton Hansson53c88442019-03-18 15:53:16 +0000315 "bar": {"device:device/vendor/blah/overlay/bar/res"},
316 "lib": {"device:device/vendor/blah/overlay/lib/res"},
Colin Cross5c4791c2019-02-01 11:44:44 -0800317 },
318 },
319 }
320
Anton Hansson53c88442019-03-18 15:53:16 +0000321 deviceResourceOverlays := []string{
Colin Cross890ff552017-11-30 20:13:19 -0800322 "device/vendor/blah/overlay",
323 "device/vendor/blah/overlay2",
324 "device/vendor/blah/static_overlay",
325 }
326
Anton Hansson53c88442019-03-18 15:53:16 +0000327 productResourceOverlays := []string{
328 "product/vendor/blah/overlay",
329 }
330
Colin Cross890ff552017-11-30 20:13:19 -0800331 fs := map[string][]byte{
332 "foo/res/res/values/strings.xml": nil,
333 "bar/res/res/values/strings.xml": nil,
Colin Cross6ed7dea2019-01-31 14:44:30 -0800334 "lib/res/res/values/strings.xml": nil,
Colin Crossbec85302019-02-13 13:15:46 -0800335 "lib2/res/res/values/strings.xml": nil,
Colin Cross890ff552017-11-30 20:13:19 -0800336 "device/vendor/blah/overlay/foo/res/values/strings.xml": nil,
337 "device/vendor/blah/overlay/bar/res/values/strings.xml": nil,
Colin Cross6ed7dea2019-01-31 14:44:30 -0800338 "device/vendor/blah/overlay/lib/res/values/strings.xml": nil,
Colin Cross890ff552017-11-30 20:13:19 -0800339 "device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil,
340 "device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil,
341 "device/vendor/blah/overlay2/res/values/strings.xml": nil,
Anton Hansson53c88442019-03-18 15:53:16 +0000342 "product/vendor/blah/overlay/foo/res/values/strings.xml": nil,
Colin Cross890ff552017-11-30 20:13:19 -0800343 }
344
345 bp := `
346 android_app {
347 name: "foo",
348 resource_dirs: ["foo/res"],
Anton Hansson53c88442019-03-18 15:53:16 +0000349 static_libs: ["lib", "lib3"],
Colin Cross890ff552017-11-30 20:13:19 -0800350 }
351
352 android_app {
353 name: "bar",
354 resource_dirs: ["bar/res"],
355 }
Colin Cross6ed7dea2019-01-31 14:44:30 -0800356
357 android_library {
358 name: "lib",
359 resource_dirs: ["lib/res"],
Colin Crossbec85302019-02-13 13:15:46 -0800360 static_libs: ["lib2"],
361 }
362
363 android_library {
364 name: "lib2",
365 resource_dirs: ["lib2/res"],
Colin Cross6ed7dea2019-01-31 14:44:30 -0800366 }
Anton Hansson53c88442019-03-18 15:53:16 +0000367
368 // This library has the same resources as lib (should not lead to dupe RROs)
369 android_library {
370 name: "lib3",
371 resource_dirs: ["lib/res"]
372 }
Colin Cross890ff552017-11-30 20:13:19 -0800373 `
374
Colin Cross5c4791c2019-02-01 11:44:44 -0800375 for _, testCase := range testCases {
Colin Cross890ff552017-11-30 20:13:19 -0800376 t.Run(testCase.name, func(t *testing.T) {
377 config := testConfig(nil)
Anton Hansson53c88442019-03-18 15:53:16 +0000378 config.TestProductVariables.DeviceResourceOverlays = deviceResourceOverlays
379 config.TestProductVariables.ProductResourceOverlays = productResourceOverlays
Colin Cross890ff552017-11-30 20:13:19 -0800380 if testCase.enforceRROTargets != nil {
Colin Crossa74ca042019-01-31 14:31:51 -0800381 config.TestProductVariables.EnforceRROTargets = testCase.enforceRROTargets
Colin Cross890ff552017-11-30 20:13:19 -0800382 }
383 if testCase.enforceRROExcludedOverlays != nil {
Colin Crossa74ca042019-01-31 14:31:51 -0800384 config.TestProductVariables.EnforceRROExcludedOverlays = testCase.enforceRROExcludedOverlays
Colin Cross890ff552017-11-30 20:13:19 -0800385 }
386
387 ctx := testAppContext(config, bp, fs)
388 run(t, ctx, config)
389
Colin Crossbec85302019-02-13 13:15:46 -0800390 resourceListToFiles := func(module android.TestingModule, list []string) (files []string) {
391 for _, o := range list {
392 res := module.MaybeOutput(o)
393 if res.Rule != nil {
394 // If the overlay is compiled as part of this module (i.e. a .arsc.flat file),
395 // verify the inputs to the .arsc.flat rule.
396 files = append(files, res.Inputs.Strings()...)
397 } else {
398 // Otherwise, verify the full path to the output of the other module
399 files = append(files, o)
Anton Hansson94c93f32019-01-30 16:03:37 +0000400 }
Colin Cross890ff552017-11-30 20:13:19 -0800401 }
Colin Crossbec85302019-02-13 13:15:46 -0800402 return files
Colin Cross890ff552017-11-30 20:13:19 -0800403 }
404
Colin Crossbec85302019-02-13 13:15:46 -0800405 getResources := func(moduleName string) (resourceFiles, overlayFiles, rroDirs []string) {
406 module := ctx.ModuleForTests(moduleName, "android_common")
407 resourceList := module.MaybeOutput("aapt2/res.list")
408 if resourceList.Rule != nil {
409 resourceFiles = resourceListToFiles(module, resourceList.Inputs.Strings())
Anton Hansson0375a4f2019-01-24 14:39:19 +0000410 }
Colin Crossbec85302019-02-13 13:15:46 -0800411 overlayList := module.MaybeOutput("aapt2/overlay.list")
412 if overlayList.Rule != nil {
413 overlayFiles = resourceListToFiles(module, overlayList.Inputs.Strings())
414 }
415
Anton Hansson53c88442019-03-18 15:53:16 +0000416 for _, d := range module.Module().(AndroidLibraryDependency).ExportedRRODirs() {
417 var prefix string
418 if d.overlayType == device {
419 prefix = "device:"
420 } else if d.overlayType == product {
421 prefix = "product:"
422 } else {
423 t.Fatalf("Unexpected overlayType %d", d.overlayType)
424 }
425 rroDirs = append(rroDirs, prefix+d.path.String())
426 }
Colin Crossbec85302019-02-13 13:15:46 -0800427
428 return resourceFiles, overlayFiles, rroDirs
429 }
430
431 modules := []string{"foo", "bar", "lib", "lib2"}
432 for _, module := range modules {
433 resourceFiles, overlayFiles, rroDirs := getResources(module)
434
435 if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[module]) {
436 t.Errorf("expected %s resource files:\n %#v\n got:\n %#v",
437 module, testCase.resourceFiles[module], resourceFiles)
438 }
439 if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[module]) {
440 t.Errorf("expected %s overlay files:\n %#v\n got:\n %#v",
441 module, testCase.overlayFiles[module], overlayFiles)
442 }
443 if !reflect.DeepEqual(rroDirs, testCase.rroDirs[module]) {
Anton Hansson0375a4f2019-01-24 14:39:19 +0000444 t.Errorf("expected %s rroDirs: %#v\n got:\n %#v",
Colin Crossbec85302019-02-13 13:15:46 -0800445 module, testCase.rroDirs[module], rroDirs)
Anton Hansson0375a4f2019-01-24 14:39:19 +0000446 }
Colin Cross890ff552017-11-30 20:13:19 -0800447 }
Colin Cross890ff552017-11-30 20:13:19 -0800448 })
449 }
450}
Colin Crossd09b0b62018-04-18 11:06:47 -0700451
452func TestAppSdkVersion(t *testing.T) {
453 testCases := []struct {
454 name string
455 sdkVersion string
456 platformSdkInt int
457 platformSdkCodename string
458 platformSdkFinal bool
459 expectedMinSdkVersion string
460 }{
461 {
462 name: "current final SDK",
463 sdkVersion: "current",
464 platformSdkInt: 27,
465 platformSdkCodename: "REL",
466 platformSdkFinal: true,
467 expectedMinSdkVersion: "27",
468 },
469 {
470 name: "current non-final SDK",
471 sdkVersion: "current",
472 platformSdkInt: 27,
473 platformSdkCodename: "OMR1",
474 platformSdkFinal: false,
475 expectedMinSdkVersion: "OMR1",
476 },
477 {
478 name: "default final SDK",
479 sdkVersion: "",
480 platformSdkInt: 27,
481 platformSdkCodename: "REL",
482 platformSdkFinal: true,
483 expectedMinSdkVersion: "27",
484 },
485 {
486 name: "default non-final SDK",
487 sdkVersion: "",
488 platformSdkInt: 27,
489 platformSdkCodename: "OMR1",
490 platformSdkFinal: false,
491 expectedMinSdkVersion: "OMR1",
492 },
493 {
494 name: "14",
495 sdkVersion: "14",
496 expectedMinSdkVersion: "14",
497 },
498 }
499
500 for _, moduleType := range []string{"android_app", "android_library"} {
501 for _, test := range testCases {
502 t.Run(moduleType+" "+test.name, func(t *testing.T) {
503 bp := fmt.Sprintf(`%s {
504 name: "foo",
505 srcs: ["a.java"],
506 sdk_version: "%s",
507 }`, moduleType, test.sdkVersion)
508
509 config := testConfig(nil)
510 config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
511 config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
512 config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
513
514 ctx := testAppContext(config, bp, nil)
515
516 run(t, ctx, config)
517
518 foo := ctx.ModuleForTests("foo", "android_common")
519 link := foo.Output("package-res.apk")
520 linkFlags := strings.Split(link.Args["flags"], " ")
521 min := android.IndexList("--min-sdk-version", linkFlags)
522 target := android.IndexList("--target-sdk-version", linkFlags)
523
524 if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 {
525 t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags)
526 }
527
528 gotMinSdkVersion := linkFlags[min+1]
529 gotTargetSdkVersion := linkFlags[target+1]
530
531 if gotMinSdkVersion != test.expectedMinSdkVersion {
532 t.Errorf("incorrect --min-sdk-version, expected %q got %q",
533 test.expectedMinSdkVersion, gotMinSdkVersion)
534 }
535
536 if gotTargetSdkVersion != test.expectedMinSdkVersion {
537 t.Errorf("incorrect --target-sdk-version, expected %q got %q",
538 test.expectedMinSdkVersion, gotTargetSdkVersion)
539 }
540 })
541 }
542 }
543}
Colin Crossa4f08812018-10-02 22:03:40 -0700544
Colin Cross47fa9d32019-03-26 10:51:39 -0700545func TestJNIABI(t *testing.T) {
546 ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
Colin Crossa4f08812018-10-02 22:03:40 -0700547 cc_library {
548 name: "libjni",
549 system_shared_libs: [],
550 stl: "none",
551 }
552
553 android_test {
554 name: "test",
555 no_framework_libs: true,
556 jni_libs: ["libjni"],
557 }
558
559 android_test {
560 name: "test_first",
561 no_framework_libs: true,
562 compile_multilib: "first",
563 jni_libs: ["libjni"],
564 }
565
566 android_test {
567 name: "test_both",
568 no_framework_libs: true,
569 compile_multilib: "both",
570 jni_libs: ["libjni"],
571 }
572
573 android_test {
574 name: "test_32",
575 no_framework_libs: true,
576 compile_multilib: "32",
577 jni_libs: ["libjni"],
578 }
579
580 android_test {
581 name: "test_64",
582 no_framework_libs: true,
583 compile_multilib: "64",
584 jni_libs: ["libjni"],
585 }
586 `)
587
Colin Crossa4f08812018-10-02 22:03:40 -0700588 testCases := []struct {
589 name string
590 abis []string
591 }{
592 {"test", []string{"arm64-v8a"}},
593 {"test_first", []string{"arm64-v8a"}},
594 {"test_both", []string{"arm64-v8a", "armeabi-v7a"}},
595 {"test_32", []string{"armeabi-v7a"}},
596 {"test_64", []string{"arm64-v8a"}},
597 }
598
599 for _, test := range testCases {
600 t.Run(test.name, func(t *testing.T) {
601 app := ctx.ModuleForTests(test.name, "android_common")
602 jniLibZip := app.Output("jnilibs.zip")
603 var abis []string
604 args := strings.Fields(jniLibZip.Args["jarArgs"])
605 for i := 0; i < len(args); i++ {
606 if args[i] == "-P" {
607 abis = append(abis, filepath.Base(args[i+1]))
608 i++
609 }
610 }
611 if !reflect.DeepEqual(abis, test.abis) {
612 t.Errorf("want abis %v, got %v", test.abis, abis)
613 }
614 })
615 }
616}
Jaewoong Jung2ad817c2019-01-18 14:27:16 -0800617
Colin Cross47fa9d32019-03-26 10:51:39 -0700618func TestJNIPackaging(t *testing.T) {
619 ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
620 cc_library {
621 name: "libjni",
622 system_shared_libs: [],
623 stl: "none",
624 }
625
626 android_app {
627 name: "app",
628 jni_libs: ["libjni"],
629 }
630
631 android_app {
632 name: "app_noembed",
633 jni_libs: ["libjni"],
634 use_embedded_native_libs: false,
635 }
636
637 android_app {
638 name: "app_embed",
639 jni_libs: ["libjni"],
640 use_embedded_native_libs: true,
641 }
642
643 android_test {
644 name: "test",
645 no_framework_libs: true,
646 jni_libs: ["libjni"],
647 }
648
649 android_test {
650 name: "test_noembed",
651 no_framework_libs: true,
652 jni_libs: ["libjni"],
653 use_embedded_native_libs: false,
654 }
655
656 android_test_helper_app {
657 name: "test_helper",
658 no_framework_libs: true,
659 jni_libs: ["libjni"],
660 }
661
662 android_test_helper_app {
663 name: "test_helper_noembed",
664 no_framework_libs: true,
665 jni_libs: ["libjni"],
666 use_embedded_native_libs: false,
667 }
668 `)
669
670 testCases := []struct {
671 name string
672 packaged bool
673 compressed bool
674 }{
675 {"app", false, false},
676 {"app_noembed", false, false},
677 {"app_embed", true, false},
678 {"test", true, false},
679 {"test_noembed", true, true},
680 {"test_helper", true, false},
681 {"test_helper_noembed", true, true},
682 }
683
684 for _, test := range testCases {
685 t.Run(test.name, func(t *testing.T) {
686 app := ctx.ModuleForTests(test.name, "android_common")
687 jniLibZip := app.MaybeOutput("jnilibs.zip")
688 if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
689 t.Errorf("expected jni packaged %v, got %v", w, g)
690 }
691
692 if jniLibZip.Rule != nil {
693 if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w {
694 t.Errorf("expected jni compressed %v, got %v", w, g)
695 }
696 }
697 })
698 }
699
700}
701
Jaewoong Jung2ad817c2019-01-18 14:27:16 -0800702func TestCertificates(t *testing.T) {
703 testCases := []struct {
704 name string
705 bp string
706 certificateOverride string
707 expected string
708 }{
709 {
710 name: "default",
711 bp: `
712 android_app {
713 name: "foo",
714 srcs: ["a.java"],
715 }
716 `,
717 certificateOverride: "",
Dan Willemsen412160e2019-04-09 21:36:26 -0700718 expected: "build/make/target/product/security/testkey.x509.pem build/make/target/product/security/testkey.pk8",
Jaewoong Jung2ad817c2019-01-18 14:27:16 -0800719 },
720 {
721 name: "module certificate property",
722 bp: `
723 android_app {
724 name: "foo",
725 srcs: ["a.java"],
726 certificate: ":new_certificate"
727 }
728
729 android_app_certificate {
730 name: "new_certificate",
731 certificate: "cert/new_cert",
732 }
733 `,
734 certificateOverride: "",
735 expected: "cert/new_cert.x509.pem cert/new_cert.pk8",
736 },
737 {
738 name: "path certificate property",
739 bp: `
740 android_app {
741 name: "foo",
742 srcs: ["a.java"],
743 certificate: "expiredkey"
744 }
745 `,
746 certificateOverride: "",
Dan Willemsen412160e2019-04-09 21:36:26 -0700747 expected: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
Jaewoong Jung2ad817c2019-01-18 14:27:16 -0800748 },
749 {
750 name: "certificate overrides",
751 bp: `
752 android_app {
753 name: "foo",
754 srcs: ["a.java"],
755 certificate: "expiredkey"
756 }
757
758 android_app_certificate {
759 name: "new_certificate",
760 certificate: "cert/new_cert",
761 }
762 `,
763 certificateOverride: "foo:new_certificate",
764 expected: "cert/new_cert.x509.pem cert/new_cert.pk8",
765 },
766 }
767
768 for _, test := range testCases {
769 t.Run(test.name, func(t *testing.T) {
770 config := testConfig(nil)
771 if test.certificateOverride != "" {
772 config.TestProductVariables.CertificateOverrides = []string{test.certificateOverride}
773 }
774 ctx := testAppContext(config, test.bp, nil)
775
776 run(t, ctx, config)
777 foo := ctx.ModuleForTests("foo", "android_common")
778
779 signapk := foo.Output("foo.apk")
780 signFlags := signapk.Args["certificates"]
781 if test.expected != signFlags {
782 t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags)
783 }
784 })
785 }
786}
Jaewoong Jung9d22a912019-01-23 16:27:47 -0800787
788func TestPackageNameOverride(t *testing.T) {
789 testCases := []struct {
790 name string
791 bp string
792 packageNameOverride string
793 expected []string
794 }{
795 {
796 name: "default",
797 bp: `
798 android_app {
799 name: "foo",
800 srcs: ["a.java"],
801 }
802 `,
803 packageNameOverride: "",
804 expected: []string{
805 buildDir + "/.intermediates/foo/android_common/foo.apk",
806 buildDir + "/target/product/test_device/system/app/foo/foo.apk",
807 },
808 },
809 {
810 name: "overridden",
811 bp: `
812 android_app {
813 name: "foo",
814 srcs: ["a.java"],
815 }
816 `,
817 packageNameOverride: "foo:bar",
818 expected: []string{
819 // The package apk should be still be the original name for test dependencies.
820 buildDir + "/.intermediates/foo/android_common/foo.apk",
821 buildDir + "/target/product/test_device/system/app/bar/bar.apk",
822 },
823 },
824 }
825
826 for _, test := range testCases {
827 t.Run(test.name, func(t *testing.T) {
828 config := testConfig(nil)
829 if test.packageNameOverride != "" {
830 config.TestProductVariables.PackageNameOverrides = []string{test.packageNameOverride}
831 }
832 ctx := testAppContext(config, test.bp, nil)
833
834 run(t, ctx, config)
835 foo := ctx.ModuleForTests("foo", "android_common")
836
837 outputs := foo.AllOutputs()
838 outputMap := make(map[string]bool)
839 for _, o := range outputs {
840 outputMap[o] = true
841 }
842 for _, e := range test.expected {
843 if _, exist := outputMap[e]; !exist {
844 t.Errorf("Can't find %q in output files.\nAll outputs:%v", e, outputs)
845 }
846 }
847 })
848 }
849}
Jaewoong Jung4102e5d2019-02-27 16:26:28 -0800850
851func TestInstrumentationTargetOverridden(t *testing.T) {
852 bp := `
853 android_app {
854 name: "foo",
855 srcs: ["a.java"],
856 }
857
858 android_test {
859 name: "bar",
860 instrumentation_for: "foo",
861 }
862 `
863 config := testConfig(nil)
864 config.TestProductVariables.ManifestPackageNameOverrides = []string{"foo:org.dandroid.bp"}
865 ctx := testAppContext(config, bp, nil)
866
867 run(t, ctx, config)
868
869 bar := ctx.ModuleForTests("bar", "android_common")
870 res := bar.Output("package-res.apk")
871 aapt2Flags := res.Args["flags"]
872 e := "--rename-instrumentation-target-package org.dandroid.bp"
873 if !strings.Contains(aapt2Flags, e) {
874 t.Errorf("target package renaming flag, %q is missing in aapt2 link flags, %q", e, aapt2Flags)
875 }
876}
Jaewoong Jung525443a2019-02-28 15:35:54 -0800877
878func TestOverrideAndroidApp(t *testing.T) {
879 ctx := testJava(t, `
880 android_app {
881 name: "foo",
882 srcs: ["a.java"],
Jaewoong Junga641ee92019-03-27 11:17:14 -0700883 certificate: "expiredkey",
Jaewoong Jung525443a2019-02-28 15:35:54 -0800884 overrides: ["baz"],
885 }
886
887 override_android_app {
888 name: "bar",
889 base: "foo",
890 certificate: ":new_certificate",
891 }
892
893 android_app_certificate {
894 name: "new_certificate",
895 certificate: "cert/new_cert",
896 }
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700897
898 override_android_app {
899 name: "baz",
900 base: "foo",
901 package_name: "org.dandroid.bp",
902 }
Jaewoong Jung525443a2019-02-28 15:35:54 -0800903 `)
904
905 expectedVariants := []struct {
906 variantName string
907 apkName string
908 apkPath string
909 signFlag string
910 overrides []string
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700911 aaptFlag string
Jaewoong Jung525443a2019-02-28 15:35:54 -0800912 }{
913 {
914 variantName: "android_common",
915 apkPath: "/target/product/test_device/system/app/foo/foo.apk",
Dan Willemsen412160e2019-04-09 21:36:26 -0700916 signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
Jaewoong Jung525443a2019-02-28 15:35:54 -0800917 overrides: []string{"baz"},
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700918 aaptFlag: "",
Jaewoong Jung525443a2019-02-28 15:35:54 -0800919 },
920 {
921 variantName: "bar_android_common",
922 apkPath: "/target/product/test_device/system/app/bar/bar.apk",
923 signFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
924 overrides: []string{"baz", "foo"},
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700925 aaptFlag: "",
926 },
927 {
928 variantName: "baz_android_common",
929 apkPath: "/target/product/test_device/system/app/baz/baz.apk",
Dan Willemsen412160e2019-04-09 21:36:26 -0700930 signFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700931 overrides: []string{"baz", "foo"},
932 aaptFlag: "--rename-manifest-package org.dandroid.bp",
Jaewoong Jung525443a2019-02-28 15:35:54 -0800933 },
934 }
935 for _, expected := range expectedVariants {
936 variant := ctx.ModuleForTests("foo", expected.variantName)
937
938 // Check the final apk name
939 outputs := variant.AllOutputs()
940 expectedApkPath := buildDir + expected.apkPath
941 found := false
942 for _, o := range outputs {
943 if o == expectedApkPath {
944 found = true
945 break
946 }
947 }
948 if !found {
949 t.Errorf("Can't find %q in output files.\nAll outputs:%v", expectedApkPath, outputs)
950 }
951
952 // Check the certificate paths
953 signapk := variant.Output("foo.apk")
954 signFlag := signapk.Args["certificates"]
955 if expected.signFlag != signFlag {
956 t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.signFlag, signFlag)
957 }
958
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700959 // Check if the overrides field values are correctly aggregated.
Jaewoong Jung525443a2019-02-28 15:35:54 -0800960 mod := variant.Module().(*AndroidApp)
961 if !reflect.DeepEqual(expected.overrides, mod.appProperties.Overrides) {
962 t.Errorf("Incorrect overrides property value, expected: %q, got: %q",
963 expected.overrides, mod.appProperties.Overrides)
964 }
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700965
966 // Check the package renaming flag, if exists.
967 res := variant.Output("package-res.apk")
968 aapt2Flags := res.Args["flags"]
969 if !strings.Contains(aapt2Flags, expected.aaptFlag) {
970 t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags)
971 }
Jaewoong Jung525443a2019-02-28 15:35:54 -0800972 }
973}
Jaewoong Jungccbb3932019-04-15 09:48:31 -0700974
975func TestAndroidAppImport(t *testing.T) {
976 ctx := testJava(t, `
977 android_app_import {
978 name: "foo",
979 apk: "prebuilts/apk/app.apk",
980 certificate: "platform",
981 dex_preopt: {
982 enabled: true,
983 },
984 }
985 `)
986
987 variant := ctx.ModuleForTests("foo", "android_common")
988
989 // Check dexpreopt outputs.
990 if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
991 variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
992 t.Errorf("can't find dexpreopt outputs")
993 }
994
995 // Check cert signing flag.
996 signedApk := variant.Output("signed/foo.apk")
997 signingFlag := signedApk.Args["certificates"]
998 expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8"
999 if expected != signingFlag {
1000 t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
1001 }
1002}
1003
1004func TestAndroidAppImport_NoDexPreopt(t *testing.T) {
1005 ctx := testJava(t, `
1006 android_app_import {
1007 name: "foo",
1008 apk: "prebuilts/apk/app.apk",
1009 certificate: "platform",
1010 dex_preopt: {
1011 enabled: false,
1012 },
1013 }
1014 `)
1015
1016 variant := ctx.ModuleForTests("foo", "android_common")
1017
1018 // Check dexpreopt outputs. They shouldn't exist.
1019 if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule != nil ||
1020 variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule != nil {
1021 t.Errorf("dexpreopt shouldn't have run.")
1022 }
1023}
1024
1025func TestAndroidAppImport_Presigned(t *testing.T) {
1026 ctx := testJava(t, `
1027 android_app_import {
1028 name: "foo",
1029 apk: "prebuilts/apk/app.apk",
1030 presigned: true,
1031 dex_preopt: {
1032 enabled: true,
1033 },
1034 }
1035 `)
1036
1037 variant := ctx.ModuleForTests("foo", "android_common")
1038
1039 // Check dexpreopt outputs.
1040 if variant.MaybeOutput("dexpreopt/oat/arm64/package.vdex").Rule == nil ||
1041 variant.MaybeOutput("dexpreopt/oat/arm64/package.odex").Rule == nil {
1042 t.Errorf("can't find dexpreopt outputs")
1043 }
1044 // Make sure stripping wasn't done.
1045 stripRule := variant.Output("dexpreopt/foo.apk")
1046 if !strings.HasPrefix(stripRule.RuleParams.Command, "cp -f") {
1047 t.Errorf("unexpected, non-skipping strip command: %q", stripRule.RuleParams.Command)
1048 }
1049
1050 // Make sure signing was skipped and aligning was done instead.
1051 if variant.MaybeOutput("signed/foo.apk").Rule != nil {
1052 t.Errorf("signing rule shouldn't be included.")
1053 }
1054 if variant.MaybeOutput("zip-aligned/foo.apk").Rule == nil {
1055 t.Errorf("can't find aligning rule")
1056 }
1057}
Jaewoong Junga5e5abc2019-04-26 14:31:50 -07001058
1059func TestAndroidAppImport_DpiVariants(t *testing.T) {
1060 bp := `
1061 android_app_import {
1062 name: "foo",
1063 apk: "prebuilts/apk/app.apk",
1064 dpi_variants: {
1065 xhdpi: {
1066 apk: "prebuilts/apk/app_xhdpi.apk",
1067 },
1068 xxhdpi: {
1069 apk: "prebuilts/apk/app_xxhdpi.apk",
1070 },
1071 },
1072 certificate: "PRESIGNED",
1073 dex_preopt: {
1074 enabled: true,
1075 },
1076 }
1077 `
1078 testCases := []struct {
1079 name string
1080 aaptPreferredConfig *string
1081 aaptPrebuiltDPI []string
1082 expected string
1083 }{
1084 {
1085 name: "no preferred",
1086 aaptPreferredConfig: nil,
1087 aaptPrebuiltDPI: []string{},
1088 expected: "prebuilts/apk/app.apk",
1089 },
1090 {
1091 name: "AAPTPreferredConfig matches",
1092 aaptPreferredConfig: proptools.StringPtr("xhdpi"),
1093 aaptPrebuiltDPI: []string{"xxhdpi", "lhdpi"},
1094 expected: "prebuilts/apk/app_xhdpi.apk",
1095 },
1096 {
1097 name: "AAPTPrebuiltDPI matches",
1098 aaptPreferredConfig: proptools.StringPtr("mdpi"),
1099 aaptPrebuiltDPI: []string{"xxhdpi", "xhdpi"},
1100 expected: "prebuilts/apk/app_xxhdpi.apk",
1101 },
1102 {
1103 name: "non-first AAPTPrebuiltDPI matches",
1104 aaptPreferredConfig: proptools.StringPtr("mdpi"),
1105 aaptPrebuiltDPI: []string{"ldpi", "xhdpi"},
1106 expected: "prebuilts/apk/app_xhdpi.apk",
1107 },
1108 {
1109 name: "no matches",
1110 aaptPreferredConfig: proptools.StringPtr("mdpi"),
1111 aaptPrebuiltDPI: []string{"ldpi", "xxxhdpi"},
1112 expected: "prebuilts/apk/app.apk",
1113 },
1114 }
1115
1116 jniRuleRe := regexp.MustCompile("^if \\(zipinfo (\\S+)")
1117 for _, test := range testCases {
1118 config := testConfig(nil)
1119 config.TestProductVariables.AAPTPreferredConfig = test.aaptPreferredConfig
1120 config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI
1121 ctx := testAppContext(config, bp, nil)
1122
1123 run(t, ctx, config)
1124
1125 variant := ctx.ModuleForTests("foo", "android_common")
1126 jniRuleCommand := variant.Output("jnis-uncompressed/foo.apk").RuleParams.Command
1127 matches := jniRuleRe.FindStringSubmatch(jniRuleCommand)
1128 if len(matches) != 2 {
1129 t.Errorf("failed to extract the src apk path from %q", jniRuleCommand)
1130 }
1131 if test.expected != matches[1] {
1132 t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1])
1133 }
1134 }
1135}