blob: 2bd44ad4a0080df40554240ee2eac9dc0326ef00 [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 (
18 "android/soong/android"
Colin Cross47fa9d32019-03-26 10:51:39 -070019 "android/soong/cc"
20
Colin Crossd09b0b62018-04-18 11:06:47 -070021 "fmt"
Colin Crossa4f08812018-10-02 22:03:40 -070022 "path/filepath"
Colin Cross3bc7ffa2017-11-22 16:19:37 -080023 "reflect"
Colin Crossb69301e2017-12-01 10:48:26 -080024 "sort"
Colin Crossd09b0b62018-04-18 11:06:47 -070025 "strings"
Colin Cross3bc7ffa2017-11-22 16:19:37 -080026 "testing"
Colin Cross43377ee2019-06-25 13:35:30 -070027
28 "github.com/google/blueprint/proptools"
Colin Cross3bc7ffa2017-11-22 16:19:37 -080029)
30
31var (
32 resourceFiles = []string{
33 "res/layout/layout.xml",
34 "res/values/strings.xml",
35 "res/values-en-rUS/strings.xml",
36 }
37
38 compiledResourceFiles = []string{
39 "aapt2/res/layout_layout.xml.flat",
40 "aapt2/res/values_strings.arsc.flat",
41 "aapt2/res/values-en-rUS_strings.arsc.flat",
42 }
43)
44
Colin Cross527012a2017-11-30 22:56:16 -080045func testAppContext(config android.Config, bp string, fs map[string][]byte) *android.TestContext {
46 appFS := map[string][]byte{}
47 for k, v := range fs {
48 appFS[k] = v
Colin Cross3bc7ffa2017-11-22 16:19:37 -080049 }
50
Colin Cross527012a2017-11-30 22:56:16 -080051 for _, file := range resourceFiles {
52 appFS[file] = nil
53 }
54
55 return testContext(config, bp, appFS)
56}
57
58func testApp(t *testing.T, bp string) *android.TestContext {
59 config := testConfig(nil)
60
61 ctx := testAppContext(config, bp, nil)
62
63 run(t, ctx, config)
64
65 return ctx
Colin Cross3bc7ffa2017-11-22 16:19:37 -080066}
67
68func TestApp(t *testing.T) {
Colin Crossa97c5d32018-03-28 14:58:31 -070069 for _, moduleType := range []string{"android_app", "android_library"} {
70 t.Run(moduleType, func(t *testing.T) {
71 ctx := testApp(t, moduleType+` {
72 name: "foo",
73 srcs: ["a.java"],
74 }
75 `)
Colin Cross3bc7ffa2017-11-22 16:19:37 -080076
Colin Crossa97c5d32018-03-28 14:58:31 -070077 foo := ctx.ModuleForTests("foo", "android_common")
Colin Cross3bc7ffa2017-11-22 16:19:37 -080078
Colin Cross31656952018-05-24 16:11:20 -070079 var expectedLinkImplicits []string
80
81 manifestFixer := foo.Output("manifest_fixer/AndroidManifest.xml")
82 expectedLinkImplicits = append(expectedLinkImplicits, manifestFixer.Output.String())
Colin Cross3bc7ffa2017-11-22 16:19:37 -080083
Colin Crossa97c5d32018-03-28 14:58:31 -070084 frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
85 expectedLinkImplicits = append(expectedLinkImplicits,
86 frameworkRes.Output("package-res.apk").Output.String())
Colin Cross3bc7ffa2017-11-22 16:19:37 -080087
Colin Crossa97c5d32018-03-28 14:58:31 -070088 // Test the mapping from input files to compiled output file names
89 compile := foo.Output(compiledResourceFiles[0])
90 if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) {
91 t.Errorf("expected aapt2 compile inputs expected:\n %#v\n got:\n %#v",
92 resourceFiles, compile.Inputs.Strings())
93 }
Colin Crossb69301e2017-12-01 10:48:26 -080094
Colin Crossa97c5d32018-03-28 14:58:31 -070095 compiledResourceOutputs := compile.Outputs.Strings()
96 sort.Strings(compiledResourceOutputs)
Colin Crossb69301e2017-12-01 10:48:26 -080097
Colin Crossa97c5d32018-03-28 14:58:31 -070098 expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
Colin Cross3bc7ffa2017-11-22 16:19:37 -080099
Colin Crossa97c5d32018-03-28 14:58:31 -0700100 list := foo.Output("aapt2/res.list")
101 expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800102
Colin Crossa97c5d32018-03-28 14:58:31 -0700103 // Check that the link rule uses
104 res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk")
105 if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) {
106 t.Errorf("expected aapt2 link implicits expected:\n %#v\n got:\n %#v",
107 expectedLinkImplicits, res.Implicits.Strings())
108 }
109 })
Colin Cross3bc7ffa2017-11-22 16:19:37 -0800110 }
111}
Colin Cross890ff552017-11-30 20:13:19 -0800112
Colin Crosse560c4a2019-03-19 16:03:11 -0700113func TestAppSplits(t *testing.T) {
114 ctx := testApp(t, `
115 android_app {
116 name: "foo",
117 srcs: ["a.java"],
118 package_splits: ["v4", "v7,hdpi"],
119 }`)
120
121 foo := ctx.ModuleForTests("foo", "android_common")
122
123 expectedOutputs := []string{
124 filepath.Join(buildDir, ".intermediates/foo/android_common/foo.apk"),
125 filepath.Join(buildDir, ".intermediates/foo/android_common/foo_v4.apk"),
126 filepath.Join(buildDir, ".intermediates/foo/android_common/foo_v7_hdpi.apk"),
127 }
128 for _, expectedOutput := range expectedOutputs {
129 foo.Output(expectedOutput)
130 }
131
132 if g, w := foo.Module().(*AndroidApp).Srcs().Strings(), expectedOutputs; !reflect.DeepEqual(g, w) {
133 t.Errorf("want Srcs() = %q, got %q", w, g)
134 }
135}
136
Colin Cross0ddae7f2019-02-07 15:30:01 -0800137func TestResourceDirs(t *testing.T) {
138 testCases := []struct {
139 name string
140 prop string
141 resources []string
142 }{
143 {
144 name: "no resource_dirs",
145 prop: "",
146 resources: []string{"res/res/values/strings.xml"},
147 },
148 {
149 name: "resource_dirs",
150 prop: `resource_dirs: ["res"]`,
151 resources: []string{"res/res/values/strings.xml"},
152 },
153 {
154 name: "empty resource_dirs",
155 prop: `resource_dirs: []`,
156 resources: nil,
157 },
158 }
159
160 fs := map[string][]byte{
161 "res/res/values/strings.xml": nil,
162 }
163
164 bp := `
165 android_app {
166 name: "foo",
167 %s
168 }
169 `
170
171 for _, testCase := range testCases {
172 t.Run(testCase.name, func(t *testing.T) {
173 config := testConfig(nil)
174 ctx := testContext(config, fmt.Sprintf(bp, testCase.prop), fs)
175 run(t, ctx, config)
176
177 module := ctx.ModuleForTests("foo", "android_common")
178 resourceList := module.MaybeOutput("aapt2/res.list")
179
180 var resources []string
181 if resourceList.Rule != nil {
182 for _, compiledResource := range resourceList.Inputs.Strings() {
183 resources = append(resources, module.Output(compiledResource).Inputs.Strings()...)
184 }
185 }
186
187 if !reflect.DeepEqual(resources, testCase.resources) {
188 t.Errorf("expected resource files %q, got %q",
189 testCase.resources, resources)
190 }
191 })
192 }
193}
194
Colin Crossbec85302019-02-13 13:15:46 -0800195func TestAndroidResources(t *testing.T) {
Colin Cross5c4791c2019-02-01 11:44:44 -0800196 testCases := []struct {
197 name string
198 enforceRROTargets []string
199 enforceRROExcludedOverlays []string
Colin Crossbec85302019-02-13 13:15:46 -0800200 resourceFiles map[string][]string
Colin Cross5c4791c2019-02-01 11:44:44 -0800201 overlayFiles map[string][]string
202 rroDirs map[string][]string
203 }{
204 {
205 name: "no RRO",
206 enforceRROTargets: nil,
207 enforceRROExcludedOverlays: nil,
Colin Crossbec85302019-02-13 13:15:46 -0800208 resourceFiles: map[string][]string{
209 "foo": nil,
210 "bar": {"bar/res/res/values/strings.xml"},
211 "lib": nil,
212 "lib2": {"lib2/res/res/values/strings.xml"},
213 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800214 overlayFiles: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800215 "foo": {
216 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800217 buildDir + "/.intermediates/lib/android_common/package-res.apk",
Anton Hansson53c88442019-03-18 15:53:16 +0000218 buildDir + "/.intermediates/lib3/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800219 "foo/res/res/values/strings.xml",
Colin Cross5c4791c2019-02-01 11:44:44 -0800220 "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
221 "device/vendor/blah/overlay/foo/res/values/strings.xml",
Anton Hansson53c88442019-03-18 15:53:16 +0000222 "product/vendor/blah/overlay/foo/res/values/strings.xml",
Colin Cross5c4791c2019-02-01 11:44:44 -0800223 },
Colin Crossbec85302019-02-13 13:15:46 -0800224 "bar": {
Colin Cross5c4791c2019-02-01 11:44:44 -0800225 "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
226 "device/vendor/blah/overlay/bar/res/values/strings.xml",
227 },
Colin Crossbec85302019-02-13 13:15:46 -0800228 "lib": {
229 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
230 "lib/res/res/values/strings.xml",
231 "device/vendor/blah/overlay/lib/res/values/strings.xml",
232 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800233 },
234 rroDirs: map[string][]string{
235 "foo": nil,
236 "bar": nil,
237 },
238 },
239 {
240 name: "enforce RRO on foo",
241 enforceRROTargets: []string{"foo"},
242 enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
Colin Crossbec85302019-02-13 13:15:46 -0800243 resourceFiles: map[string][]string{
244 "foo": nil,
245 "bar": {"bar/res/res/values/strings.xml"},
246 "lib": nil,
247 "lib2": {"lib2/res/res/values/strings.xml"},
248 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800249 overlayFiles: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800250 "foo": {
251 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800252 buildDir + "/.intermediates/lib/android_common/package-res.apk",
Anton Hansson53c88442019-03-18 15:53:16 +0000253 buildDir + "/.intermediates/lib3/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800254 "foo/res/res/values/strings.xml",
255 "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
256 },
Colin Crossbec85302019-02-13 13:15:46 -0800257 "bar": {
Colin Cross5c4791c2019-02-01 11:44:44 -0800258 "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
259 "device/vendor/blah/overlay/bar/res/values/strings.xml",
260 },
Colin Crossbec85302019-02-13 13:15:46 -0800261 "lib": {
262 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
263 "lib/res/res/values/strings.xml",
264 "device/vendor/blah/overlay/lib/res/values/strings.xml",
265 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800266 },
Colin Crossc1c37552019-01-31 11:42:41 -0800267
Colin Cross5c4791c2019-02-01 11:44:44 -0800268 rroDirs: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800269 "foo": {
Anton Hansson53c88442019-03-18 15:53:16 +0000270 "device:device/vendor/blah/overlay/foo/res",
Colin Crossc1c37552019-01-31 11:42:41 -0800271 // Enforce RRO on "foo" could imply RRO on static dependencies, but for now it doesn't.
272 // "device/vendor/blah/overlay/lib/res",
Anton Hansson53c88442019-03-18 15:53:16 +0000273 "product:product/vendor/blah/overlay/foo/res",
Colin Crossc1c37552019-01-31 11:42:41 -0800274 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800275 "bar": nil,
Colin Crossbec85302019-02-13 13:15:46 -0800276 "lib": nil,
Colin Cross5c4791c2019-02-01 11:44:44 -0800277 },
278 },
279 {
280 name: "enforce RRO on all",
281 enforceRROTargets: []string{"*"},
282 enforceRROExcludedOverlays: []string{
283 // Excluding specific apps/res directories also allowed.
284 "device/vendor/blah/static_overlay/foo",
285 "device/vendor/blah/static_overlay/bar/res",
286 },
Colin Crossbec85302019-02-13 13:15:46 -0800287 resourceFiles: map[string][]string{
288 "foo": nil,
289 "bar": {"bar/res/res/values/strings.xml"},
290 "lib": nil,
291 "lib2": {"lib2/res/res/values/strings.xml"},
292 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800293 overlayFiles: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800294 "foo": {
295 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800296 buildDir + "/.intermediates/lib/android_common/package-res.apk",
Anton Hansson53c88442019-03-18 15:53:16 +0000297 buildDir + "/.intermediates/lib3/android_common/package-res.apk",
Colin Cross6ed7dea2019-01-31 14:44:30 -0800298 "foo/res/res/values/strings.xml",
299 "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
300 },
Colin Crossbec85302019-02-13 13:15:46 -0800301 "bar": {"device/vendor/blah/static_overlay/bar/res/values/strings.xml"},
302 "lib": {
303 buildDir + "/.intermediates/lib2/android_common/package-res.apk",
304 "lib/res/res/values/strings.xml",
305 },
Colin Cross5c4791c2019-02-01 11:44:44 -0800306 },
307 rroDirs: map[string][]string{
Colin Crossbec85302019-02-13 13:15:46 -0800308 "foo": {
Anton Hansson53c88442019-03-18 15:53:16 +0000309 "device:device/vendor/blah/overlay/foo/res",
310 "product:product/vendor/blah/overlay/foo/res",
311 // Lib dep comes after the direct deps
312 "device:device/vendor/blah/overlay/lib/res",
Colin Crossc1c37552019-01-31 11:42:41 -0800313 },
Anton Hansson53c88442019-03-18 15:53:16 +0000314 "bar": {"device:device/vendor/blah/overlay/bar/res"},
315 "lib": {"device:device/vendor/blah/overlay/lib/res"},
Colin Cross5c4791c2019-02-01 11:44:44 -0800316 },
317 },
318 }
319
Anton Hansson53c88442019-03-18 15:53:16 +0000320 deviceResourceOverlays := []string{
Colin Cross890ff552017-11-30 20:13:19 -0800321 "device/vendor/blah/overlay",
322 "device/vendor/blah/overlay2",
323 "device/vendor/blah/static_overlay",
324 }
325
Anton Hansson53c88442019-03-18 15:53:16 +0000326 productResourceOverlays := []string{
327 "product/vendor/blah/overlay",
328 }
329
Colin Cross890ff552017-11-30 20:13:19 -0800330 fs := map[string][]byte{
331 "foo/res/res/values/strings.xml": nil,
332 "bar/res/res/values/strings.xml": nil,
Colin Cross6ed7dea2019-01-31 14:44:30 -0800333 "lib/res/res/values/strings.xml": nil,
Colin Crossbec85302019-02-13 13:15:46 -0800334 "lib2/res/res/values/strings.xml": nil,
Colin Cross890ff552017-11-30 20:13:19 -0800335 "device/vendor/blah/overlay/foo/res/values/strings.xml": nil,
336 "device/vendor/blah/overlay/bar/res/values/strings.xml": nil,
Colin Cross6ed7dea2019-01-31 14:44:30 -0800337 "device/vendor/blah/overlay/lib/res/values/strings.xml": nil,
Colin Cross890ff552017-11-30 20:13:19 -0800338 "device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil,
339 "device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil,
340 "device/vendor/blah/overlay2/res/values/strings.xml": nil,
Anton Hansson53c88442019-03-18 15:53:16 +0000341 "product/vendor/blah/overlay/foo/res/values/strings.xml": nil,
Colin Cross890ff552017-11-30 20:13:19 -0800342 }
343
344 bp := `
345 android_app {
346 name: "foo",
347 resource_dirs: ["foo/res"],
Anton Hansson53c88442019-03-18 15:53:16 +0000348 static_libs: ["lib", "lib3"],
Colin Cross890ff552017-11-30 20:13:19 -0800349 }
350
351 android_app {
352 name: "bar",
353 resource_dirs: ["bar/res"],
354 }
Colin Cross6ed7dea2019-01-31 14:44:30 -0800355
356 android_library {
357 name: "lib",
358 resource_dirs: ["lib/res"],
Colin Crossbec85302019-02-13 13:15:46 -0800359 static_libs: ["lib2"],
360 }
361
362 android_library {
363 name: "lib2",
364 resource_dirs: ["lib2/res"],
Colin Cross6ed7dea2019-01-31 14:44:30 -0800365 }
Anton Hansson53c88442019-03-18 15:53:16 +0000366
367 // This library has the same resources as lib (should not lead to dupe RROs)
368 android_library {
369 name: "lib3",
370 resource_dirs: ["lib/res"]
371 }
Colin Cross890ff552017-11-30 20:13:19 -0800372 `
373
Colin Cross5c4791c2019-02-01 11:44:44 -0800374 for _, testCase := range testCases {
Colin Cross890ff552017-11-30 20:13:19 -0800375 t.Run(testCase.name, func(t *testing.T) {
376 config := testConfig(nil)
Anton Hansson53c88442019-03-18 15:53:16 +0000377 config.TestProductVariables.DeviceResourceOverlays = deviceResourceOverlays
378 config.TestProductVariables.ProductResourceOverlays = productResourceOverlays
Colin Cross890ff552017-11-30 20:13:19 -0800379 if testCase.enforceRROTargets != nil {
Colin Crossa74ca042019-01-31 14:31:51 -0800380 config.TestProductVariables.EnforceRROTargets = testCase.enforceRROTargets
Colin Cross890ff552017-11-30 20:13:19 -0800381 }
382 if testCase.enforceRROExcludedOverlays != nil {
Colin Crossa74ca042019-01-31 14:31:51 -0800383 config.TestProductVariables.EnforceRROExcludedOverlays = testCase.enforceRROExcludedOverlays
Colin Cross890ff552017-11-30 20:13:19 -0800384 }
385
386 ctx := testAppContext(config, bp, fs)
387 run(t, ctx, config)
388
Colin Crossbec85302019-02-13 13:15:46 -0800389 resourceListToFiles := func(module android.TestingModule, list []string) (files []string) {
390 for _, o := range list {
391 res := module.MaybeOutput(o)
392 if res.Rule != nil {
393 // If the overlay is compiled as part of this module (i.e. a .arsc.flat file),
394 // verify the inputs to the .arsc.flat rule.
395 files = append(files, res.Inputs.Strings()...)
396 } else {
397 // Otherwise, verify the full path to the output of the other module
398 files = append(files, o)
Anton Hansson94c93f32019-01-30 16:03:37 +0000399 }
Colin Cross890ff552017-11-30 20:13:19 -0800400 }
Colin Crossbec85302019-02-13 13:15:46 -0800401 return files
Colin Cross890ff552017-11-30 20:13:19 -0800402 }
403
Colin Crossbec85302019-02-13 13:15:46 -0800404 getResources := func(moduleName string) (resourceFiles, overlayFiles, rroDirs []string) {
405 module := ctx.ModuleForTests(moduleName, "android_common")
406 resourceList := module.MaybeOutput("aapt2/res.list")
407 if resourceList.Rule != nil {
408 resourceFiles = resourceListToFiles(module, resourceList.Inputs.Strings())
Anton Hansson0375a4f2019-01-24 14:39:19 +0000409 }
Colin Crossbec85302019-02-13 13:15:46 -0800410 overlayList := module.MaybeOutput("aapt2/overlay.list")
411 if overlayList.Rule != nil {
412 overlayFiles = resourceListToFiles(module, overlayList.Inputs.Strings())
413 }
414
Anton Hansson53c88442019-03-18 15:53:16 +0000415 for _, d := range module.Module().(AndroidLibraryDependency).ExportedRRODirs() {
416 var prefix string
417 if d.overlayType == device {
418 prefix = "device:"
419 } else if d.overlayType == product {
420 prefix = "product:"
421 } else {
422 t.Fatalf("Unexpected overlayType %d", d.overlayType)
423 }
424 rroDirs = append(rroDirs, prefix+d.path.String())
425 }
Colin Crossbec85302019-02-13 13:15:46 -0800426
427 return resourceFiles, overlayFiles, rroDirs
428 }
429
430 modules := []string{"foo", "bar", "lib", "lib2"}
431 for _, module := range modules {
432 resourceFiles, overlayFiles, rroDirs := getResources(module)
433
434 if !reflect.DeepEqual(resourceFiles, testCase.resourceFiles[module]) {
435 t.Errorf("expected %s resource files:\n %#v\n got:\n %#v",
436 module, testCase.resourceFiles[module], resourceFiles)
437 }
438 if !reflect.DeepEqual(overlayFiles, testCase.overlayFiles[module]) {
439 t.Errorf("expected %s overlay files:\n %#v\n got:\n %#v",
440 module, testCase.overlayFiles[module], overlayFiles)
441 }
442 if !reflect.DeepEqual(rroDirs, testCase.rroDirs[module]) {
Anton Hansson0375a4f2019-01-24 14:39:19 +0000443 t.Errorf("expected %s rroDirs: %#v\n got:\n %#v",
Colin Crossbec85302019-02-13 13:15:46 -0800444 module, testCase.rroDirs[module], rroDirs)
Anton Hansson0375a4f2019-01-24 14:39:19 +0000445 }
Colin Cross890ff552017-11-30 20:13:19 -0800446 }
Colin Cross890ff552017-11-30 20:13:19 -0800447 })
448 }
449}
Colin Crossd09b0b62018-04-18 11:06:47 -0700450
451func TestAppSdkVersion(t *testing.T) {
452 testCases := []struct {
453 name string
454 sdkVersion string
455 platformSdkInt int
456 platformSdkCodename string
457 platformSdkFinal bool
458 expectedMinSdkVersion string
459 }{
460 {
461 name: "current final SDK",
462 sdkVersion: "current",
463 platformSdkInt: 27,
464 platformSdkCodename: "REL",
465 platformSdkFinal: true,
466 expectedMinSdkVersion: "27",
467 },
468 {
469 name: "current non-final SDK",
470 sdkVersion: "current",
471 platformSdkInt: 27,
472 platformSdkCodename: "OMR1",
473 platformSdkFinal: false,
474 expectedMinSdkVersion: "OMR1",
475 },
476 {
477 name: "default final SDK",
478 sdkVersion: "",
479 platformSdkInt: 27,
480 platformSdkCodename: "REL",
481 platformSdkFinal: true,
482 expectedMinSdkVersion: "27",
483 },
484 {
485 name: "default non-final SDK",
486 sdkVersion: "",
487 platformSdkInt: 27,
488 platformSdkCodename: "OMR1",
489 platformSdkFinal: false,
490 expectedMinSdkVersion: "OMR1",
491 },
492 {
493 name: "14",
494 sdkVersion: "14",
495 expectedMinSdkVersion: "14",
496 },
497 }
498
499 for _, moduleType := range []string{"android_app", "android_library"} {
500 for _, test := range testCases {
501 t.Run(moduleType+" "+test.name, func(t *testing.T) {
502 bp := fmt.Sprintf(`%s {
503 name: "foo",
504 srcs: ["a.java"],
505 sdk_version: "%s",
506 }`, moduleType, test.sdkVersion)
507
508 config := testConfig(nil)
509 config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
510 config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
511 config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
512
513 ctx := testAppContext(config, bp, nil)
514
515 run(t, ctx, config)
516
517 foo := ctx.ModuleForTests("foo", "android_common")
518 link := foo.Output("package-res.apk")
519 linkFlags := strings.Split(link.Args["flags"], " ")
520 min := android.IndexList("--min-sdk-version", linkFlags)
521 target := android.IndexList("--target-sdk-version", linkFlags)
522
523 if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 {
524 t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags)
525 }
526
527 gotMinSdkVersion := linkFlags[min+1]
528 gotTargetSdkVersion := linkFlags[target+1]
529
530 if gotMinSdkVersion != test.expectedMinSdkVersion {
531 t.Errorf("incorrect --min-sdk-version, expected %q got %q",
532 test.expectedMinSdkVersion, gotMinSdkVersion)
533 }
534
535 if gotTargetSdkVersion != test.expectedMinSdkVersion {
536 t.Errorf("incorrect --target-sdk-version, expected %q got %q",
537 test.expectedMinSdkVersion, gotTargetSdkVersion)
538 }
539 })
540 }
541 }
542}
Colin Crossa4f08812018-10-02 22:03:40 -0700543
Colin Cross47fa9d32019-03-26 10:51:39 -0700544func TestJNIABI(t *testing.T) {
545 ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
Colin Crossa4f08812018-10-02 22:03:40 -0700546 cc_library {
547 name: "libjni",
548 system_shared_libs: [],
549 stl: "none",
550 }
551
552 android_test {
553 name: "test",
554 no_framework_libs: true,
555 jni_libs: ["libjni"],
556 }
557
558 android_test {
559 name: "test_first",
560 no_framework_libs: true,
561 compile_multilib: "first",
562 jni_libs: ["libjni"],
563 }
564
565 android_test {
566 name: "test_both",
567 no_framework_libs: true,
568 compile_multilib: "both",
569 jni_libs: ["libjni"],
570 }
571
572 android_test {
573 name: "test_32",
574 no_framework_libs: true,
575 compile_multilib: "32",
576 jni_libs: ["libjni"],
577 }
578
579 android_test {
580 name: "test_64",
581 no_framework_libs: true,
582 compile_multilib: "64",
583 jni_libs: ["libjni"],
584 }
585 `)
586
Colin Crossa4f08812018-10-02 22:03:40 -0700587 testCases := []struct {
588 name string
589 abis []string
590 }{
591 {"test", []string{"arm64-v8a"}},
592 {"test_first", []string{"arm64-v8a"}},
593 {"test_both", []string{"arm64-v8a", "armeabi-v7a"}},
594 {"test_32", []string{"armeabi-v7a"}},
595 {"test_64", []string{"arm64-v8a"}},
596 }
597
598 for _, test := range testCases {
599 t.Run(test.name, func(t *testing.T) {
600 app := ctx.ModuleForTests(test.name, "android_common")
601 jniLibZip := app.Output("jnilibs.zip")
602 var abis []string
603 args := strings.Fields(jniLibZip.Args["jarArgs"])
604 for i := 0; i < len(args); i++ {
605 if args[i] == "-P" {
606 abis = append(abis, filepath.Base(args[i+1]))
607 i++
608 }
609 }
610 if !reflect.DeepEqual(abis, test.abis) {
611 t.Errorf("want abis %v, got %v", test.abis, abis)
612 }
613 })
614 }
615}
Jaewoong Jung2ad817c2019-01-18 14:27:16 -0800616
Colin Cross47fa9d32019-03-26 10:51:39 -0700617func TestJNIPackaging(t *testing.T) {
618 ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
619 cc_library {
620 name: "libjni",
621 system_shared_libs: [],
622 stl: "none",
623 }
624
625 android_app {
626 name: "app",
627 jni_libs: ["libjni"],
628 }
629
630 android_app {
631 name: "app_noembed",
632 jni_libs: ["libjni"],
633 use_embedded_native_libs: false,
634 }
635
636 android_app {
637 name: "app_embed",
638 jni_libs: ["libjni"],
639 use_embedded_native_libs: true,
640 }
641
642 android_test {
643 name: "test",
644 no_framework_libs: true,
645 jni_libs: ["libjni"],
646 }
647
648 android_test {
649 name: "test_noembed",
650 no_framework_libs: true,
651 jni_libs: ["libjni"],
652 use_embedded_native_libs: false,
653 }
654
655 android_test_helper_app {
656 name: "test_helper",
657 no_framework_libs: true,
658 jni_libs: ["libjni"],
659 }
660
661 android_test_helper_app {
662 name: "test_helper_noembed",
663 no_framework_libs: true,
664 jni_libs: ["libjni"],
665 use_embedded_native_libs: false,
666 }
667 `)
668
669 testCases := []struct {
670 name string
671 packaged bool
672 compressed bool
673 }{
674 {"app", false, false},
675 {"app_noembed", false, false},
676 {"app_embed", true, false},
677 {"test", true, false},
678 {"test_noembed", true, true},
679 {"test_helper", true, false},
680 {"test_helper_noembed", true, true},
681 }
682
683 for _, test := range testCases {
684 t.Run(test.name, func(t *testing.T) {
685 app := ctx.ModuleForTests(test.name, "android_common")
686 jniLibZip := app.MaybeOutput("jnilibs.zip")
687 if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
688 t.Errorf("expected jni packaged %v, got %v", w, g)
689 }
690
691 if jniLibZip.Rule != nil {
692 if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w {
693 t.Errorf("expected jni compressed %v, got %v", w, g)
694 }
695 }
696 })
697 }
698
699}
700
Jaewoong Jung2ad817c2019-01-18 14:27:16 -0800701func TestCertificates(t *testing.T) {
702 testCases := []struct {
703 name string
704 bp string
705 certificateOverride string
706 expected string
707 }{
708 {
709 name: "default",
710 bp: `
711 android_app {
712 name: "foo",
713 srcs: ["a.java"],
714 }
715 `,
716 certificateOverride: "",
717 expected: "build/target/product/security/testkey.x509.pem build/target/product/security/testkey.pk8",
718 },
719 {
720 name: "module certificate property",
721 bp: `
722 android_app {
723 name: "foo",
724 srcs: ["a.java"],
725 certificate: ":new_certificate"
726 }
727
728 android_app_certificate {
729 name: "new_certificate",
730 certificate: "cert/new_cert",
731 }
732 `,
733 certificateOverride: "",
734 expected: "cert/new_cert.x509.pem cert/new_cert.pk8",
735 },
736 {
737 name: "path certificate property",
738 bp: `
739 android_app {
740 name: "foo",
741 srcs: ["a.java"],
742 certificate: "expiredkey"
743 }
744 `,
745 certificateOverride: "",
746 expected: "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8",
747 },
748 {
749 name: "certificate overrides",
750 bp: `
751 android_app {
752 name: "foo",
753 srcs: ["a.java"],
754 certificate: "expiredkey"
755 }
756
757 android_app_certificate {
758 name: "new_certificate",
759 certificate: "cert/new_cert",
760 }
761 `,
762 certificateOverride: "foo:new_certificate",
763 expected: "cert/new_cert.x509.pem cert/new_cert.pk8",
764 },
765 }
766
767 for _, test := range testCases {
768 t.Run(test.name, func(t *testing.T) {
769 config := testConfig(nil)
770 if test.certificateOverride != "" {
771 config.TestProductVariables.CertificateOverrides = []string{test.certificateOverride}
772 }
773 ctx := testAppContext(config, test.bp, nil)
774
775 run(t, ctx, config)
776 foo := ctx.ModuleForTests("foo", "android_common")
777
778 signapk := foo.Output("foo.apk")
779 signFlags := signapk.Args["certificates"]
780 if test.expected != signFlags {
781 t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags)
782 }
783 })
784 }
785}
Jaewoong Jung9d22a912019-01-23 16:27:47 -0800786
787func TestPackageNameOverride(t *testing.T) {
788 testCases := []struct {
789 name string
790 bp string
791 packageNameOverride string
792 expected []string
793 }{
794 {
795 name: "default",
796 bp: `
797 android_app {
798 name: "foo",
799 srcs: ["a.java"],
800 }
801 `,
802 packageNameOverride: "",
803 expected: []string{
804 buildDir + "/.intermediates/foo/android_common/foo.apk",
805 buildDir + "/target/product/test_device/system/app/foo/foo.apk",
806 },
807 },
808 {
809 name: "overridden",
810 bp: `
811 android_app {
812 name: "foo",
813 srcs: ["a.java"],
814 }
815 `,
816 packageNameOverride: "foo:bar",
817 expected: []string{
818 // The package apk should be still be the original name for test dependencies.
819 buildDir + "/.intermediates/foo/android_common/foo.apk",
820 buildDir + "/target/product/test_device/system/app/bar/bar.apk",
821 },
822 },
823 }
824
825 for _, test := range testCases {
826 t.Run(test.name, func(t *testing.T) {
827 config := testConfig(nil)
828 if test.packageNameOverride != "" {
829 config.TestProductVariables.PackageNameOverrides = []string{test.packageNameOverride}
830 }
831 ctx := testAppContext(config, test.bp, nil)
832
833 run(t, ctx, config)
834 foo := ctx.ModuleForTests("foo", "android_common")
835
836 outputs := foo.AllOutputs()
837 outputMap := make(map[string]bool)
838 for _, o := range outputs {
839 outputMap[o] = true
840 }
841 for _, e := range test.expected {
842 if _, exist := outputMap[e]; !exist {
843 t.Errorf("Can't find %q in output files.\nAll outputs:%v", e, outputs)
844 }
845 }
846 })
847 }
848}
Jaewoong Jung4102e5d2019-02-27 16:26:28 -0800849
850func TestInstrumentationTargetOverridden(t *testing.T) {
851 bp := `
852 android_app {
853 name: "foo",
854 srcs: ["a.java"],
855 }
856
857 android_test {
858 name: "bar",
859 instrumentation_for: "foo",
860 }
861 `
862 config := testConfig(nil)
863 config.TestProductVariables.ManifestPackageNameOverrides = []string{"foo:org.dandroid.bp"}
864 ctx := testAppContext(config, bp, nil)
865
866 run(t, ctx, config)
867
868 bar := ctx.ModuleForTests("bar", "android_common")
869 res := bar.Output("package-res.apk")
870 aapt2Flags := res.Args["flags"]
871 e := "--rename-instrumentation-target-package org.dandroid.bp"
872 if !strings.Contains(aapt2Flags, e) {
873 t.Errorf("target package renaming flag, %q is missing in aapt2 link flags, %q", e, aapt2Flags)
874 }
875}
Jaewoong Jung525443a2019-02-28 15:35:54 -0800876
877func TestOverrideAndroidApp(t *testing.T) {
878 ctx := testJava(t, `
879 android_app {
880 name: "foo",
881 srcs: ["a.java"],
Jaewoong Junga641ee92019-03-27 11:17:14 -0700882 certificate: "expiredkey",
Jaewoong Jung525443a2019-02-28 15:35:54 -0800883 overrides: ["baz"],
884 }
885
886 override_android_app {
887 name: "bar",
888 base: "foo",
889 certificate: ":new_certificate",
890 }
891
892 android_app_certificate {
893 name: "new_certificate",
894 certificate: "cert/new_cert",
895 }
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700896
897 override_android_app {
898 name: "baz",
899 base: "foo",
900 package_name: "org.dandroid.bp",
901 }
Jaewoong Jung525443a2019-02-28 15:35:54 -0800902 `)
903
904 expectedVariants := []struct {
905 variantName string
906 apkName string
907 apkPath string
908 signFlag string
909 overrides []string
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700910 aaptFlag string
Jaewoong Jung525443a2019-02-28 15:35:54 -0800911 }{
912 {
913 variantName: "android_common",
914 apkPath: "/target/product/test_device/system/app/foo/foo.apk",
Jaewoong Junga641ee92019-03-27 11:17:14 -0700915 signFlag: "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8",
Jaewoong Jung525443a2019-02-28 15:35:54 -0800916 overrides: []string{"baz"},
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700917 aaptFlag: "",
Jaewoong Jung525443a2019-02-28 15:35:54 -0800918 },
919 {
920 variantName: "bar_android_common",
921 apkPath: "/target/product/test_device/system/app/bar/bar.apk",
922 signFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
923 overrides: []string{"baz", "foo"},
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700924 aaptFlag: "",
925 },
926 {
927 variantName: "baz_android_common",
928 apkPath: "/target/product/test_device/system/app/baz/baz.apk",
Jaewoong Junga641ee92019-03-27 11:17:14 -0700929 signFlag: "build/target/product/security/expiredkey.x509.pem build/target/product/security/expiredkey.pk8",
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700930 overrides: []string{"baz", "foo"},
931 aaptFlag: "--rename-manifest-package org.dandroid.bp",
Jaewoong Jung525443a2019-02-28 15:35:54 -0800932 },
933 }
934 for _, expected := range expectedVariants {
935 variant := ctx.ModuleForTests("foo", expected.variantName)
936
937 // Check the final apk name
938 outputs := variant.AllOutputs()
939 expectedApkPath := buildDir + expected.apkPath
940 found := false
941 for _, o := range outputs {
942 if o == expectedApkPath {
943 found = true
944 break
945 }
946 }
947 if !found {
948 t.Errorf("Can't find %q in output files.\nAll outputs:%v", expectedApkPath, outputs)
949 }
950
951 // Check the certificate paths
952 signapk := variant.Output("foo.apk")
953 signFlag := signapk.Args["certificates"]
954 if expected.signFlag != signFlag {
955 t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected.signFlag, signFlag)
956 }
957
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700958 // Check if the overrides field values are correctly aggregated.
Jaewoong Jung525443a2019-02-28 15:35:54 -0800959 mod := variant.Module().(*AndroidApp)
960 if !reflect.DeepEqual(expected.overrides, mod.appProperties.Overrides) {
961 t.Errorf("Incorrect overrides property value, expected: %q, got: %q",
962 expected.overrides, mod.appProperties.Overrides)
963 }
Jaewoong Jung6f373f62019-03-13 10:13:24 -0700964
965 // Check the package renaming flag, if exists.
966 res := variant.Output("package-res.apk")
967 aapt2Flags := res.Args["flags"]
968 if !strings.Contains(aapt2Flags, expected.aaptFlag) {
969 t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags)
970 }
Jaewoong Jung525443a2019-02-28 15:35:54 -0800971 }
972}
Jaewoong Jung5c6572e2019-06-17 17:40:56 -0700973
974func TestEmbedNotice(t *testing.T) {
975 ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
976 android_app {
977 name: "foo",
978 srcs: ["a.java"],
979 static_libs: ["javalib"],
980 jni_libs: ["libjni"],
981 notice: "APP_NOTICE",
982 embed_notices: true,
983 }
984
985 // No embed_notice flag
986 android_app {
987 name: "bar",
988 srcs: ["a.java"],
989 jni_libs: ["libjni"],
990 notice: "APP_NOTICE",
991 }
992
993 // No NOTICE files
994 android_app {
995 name: "baz",
996 srcs: ["a.java"],
997 embed_notices: true,
998 }
999
1000 cc_library {
1001 name: "libjni",
1002 system_shared_libs: [],
1003 stl: "none",
1004 notice: "LIB_NOTICE",
1005 }
1006
1007 java_library {
1008 name: "javalib",
1009 srcs: [
1010 ":gen",
1011 ],
1012 }
1013
1014 genrule {
1015 name: "gen",
1016 tools: ["gentool"],
1017 out: ["gen.java"],
1018 notice: "GENRULE_NOTICE",
1019 }
1020
1021 java_binary_host {
1022 name: "gentool",
1023 srcs: ["b.java"],
1024 notice: "TOOL_NOTICE",
1025 }
1026 `)
1027
1028 // foo has NOTICE files to process, and embed_notices is true.
1029 foo := ctx.ModuleForTests("foo", "android_common")
1030 // verify merge notices rule.
1031 mergeNotices := foo.Rule("mergeNoticesRule")
1032 noticeInputs := mergeNotices.Inputs.Strings()
1033 // TOOL_NOTICE should be excluded as it's a host module.
1034 if len(mergeNotices.Inputs) != 3 {
1035 t.Errorf("number of input notice files: expected = 3, actual = %q", noticeInputs)
1036 }
1037 if !inList("APP_NOTICE", noticeInputs) {
1038 t.Errorf("APP_NOTICE is missing from notice files, %q", noticeInputs)
1039 }
1040 if !inList("LIB_NOTICE", noticeInputs) {
1041 t.Errorf("LIB_NOTICE is missing from notice files, %q", noticeInputs)
1042 }
1043 if !inList("GENRULE_NOTICE", noticeInputs) {
1044 t.Errorf("GENRULE_NOTICE is missing from notice files, %q", noticeInputs)
1045 }
1046 // aapt2 flags should include -A <NOTICE dir> so that its contents are put in the APK's /assets.
1047 res := foo.Output("package-res.apk")
1048 aapt2Flags := res.Args["flags"]
1049 e := "-A " + buildDir + "/.intermediates/foo/android_common/NOTICE"
1050 if !strings.Contains(aapt2Flags, e) {
1051 t.Errorf("asset dir flag for NOTICE, %q is missing in aapt2 link flags, %q", e, aapt2Flags)
1052 }
1053
1054 // bar has NOTICE files to process, but embed_notices is not set.
1055 bar := ctx.ModuleForTests("bar", "android_common")
1056 mergeNotices = bar.MaybeRule("mergeNoticesRule")
1057 if mergeNotices.Rule != nil {
1058 t.Errorf("mergeNotices shouldn't have run for bar")
1059 }
1060
1061 // baz's embed_notice is true, but it doesn't have any NOTICE files.
1062 baz := ctx.ModuleForTests("baz", "android_common")
1063 mergeNotices = baz.MaybeRule("mergeNoticesRule")
1064 if mergeNotices.Rule != nil {
1065 t.Errorf("mergeNotices shouldn't have run for baz")
1066 }
1067}
Colin Cross43377ee2019-06-25 13:35:30 -07001068
1069func TestUncompressDex(t *testing.T) {
1070 testCases := []struct {
1071 name string
1072 bp string
1073
1074 uncompressedPlatform bool
1075 uncompressedUnbundled bool
1076 }{
1077 {
1078 name: "normal",
1079 bp: `
1080 android_app {
1081 name: "foo",
1082 srcs: ["a.java"],
1083 }
1084 `,
1085 uncompressedPlatform: true,
1086 uncompressedUnbundled: false,
1087 },
1088 {
1089 name: "use_embedded_dex",
1090 bp: `
1091 android_app {
1092 name: "foo",
1093 use_embedded_dex: true,
1094 srcs: ["a.java"],
1095 }
1096 `,
1097 uncompressedPlatform: true,
1098 uncompressedUnbundled: true,
1099 },
1100 {
1101 name: "privileged",
1102 bp: `
1103 android_app {
1104 name: "foo",
1105 privileged: true,
1106 srcs: ["a.java"],
1107 }
1108 `,
1109 uncompressedPlatform: true,
1110 uncompressedUnbundled: true,
1111 },
1112 }
1113
1114 test := func(t *testing.T, bp string, want bool, unbundled bool) {
1115 t.Helper()
1116
1117 config := testConfig(nil)
1118 if unbundled {
1119 config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
1120 }
1121
1122 ctx := testAppContext(config, bp, nil)
1123
1124 run(t, ctx, config)
1125
1126 foo := ctx.ModuleForTests("foo", "android_common")
1127 dex := foo.Rule("r8")
1128 uncompressedInDexJar := strings.Contains(dex.Args["zipFlags"], "-L 0")
1129 aligned := foo.MaybeRule("zipalign").Rule != nil
1130
1131 if uncompressedInDexJar != want {
1132 t.Errorf("want uncompressed in dex %v, got %v", want, uncompressedInDexJar)
1133 }
1134
1135 if aligned != want {
1136 t.Errorf("want aligned %v, got %v", want, aligned)
1137 }
1138 }
1139
1140 for _, tt := range testCases {
1141 t.Run(tt.name, func(t *testing.T) {
1142 t.Run("platform", func(t *testing.T) {
1143 test(t, tt.bp, tt.uncompressedPlatform, false)
1144 })
1145 t.Run("unbundled", func(t *testing.T) {
1146 test(t, tt.bp, tt.uncompressedUnbundled, true)
1147 })
1148 })
1149 }
1150}