1// Copyright 2020 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 "reflect" 19 "strings" 20 "testing" 21 22 "android/soong/android" 23 "android/soong/shared" 24) 25 26func TestRuntimeResourceOverlay(t *testing.T) { 27 fs := android.MockFS{ 28 "baz/res/res/values/strings.xml": nil, 29 "bar/res/res/values/strings.xml": nil, 30 } 31 bp := ` 32 runtime_resource_overlay { 33 name: "foo", 34 certificate: "platform", 35 lineage: "lineage.bin", 36 rotationMinSdkVersion: "32", 37 product_specific: true, 38 static_libs: ["bar"], 39 resource_libs: ["baz"], 40 aaptflags: ["--keep-raw-values"], 41 } 42 43 runtime_resource_overlay { 44 name: "foo_themed", 45 certificate: "platform", 46 product_specific: true, 47 theme: "faza", 48 overrides: ["foo"], 49 } 50 51 android_library { 52 name: "bar", 53 resource_dirs: ["bar/res"], 54 } 55 56 android_app { 57 name: "baz", 58 sdk_version: "current", 59 resource_dirs: ["baz/res"], 60 } 61 ` 62 63 result := android.GroupFixturePreparers( 64 PrepareForTestWithJavaDefaultModules, 65 android.FixtureModifyConfig(android.SetKatiEnabledForTests), 66 fs.AddToFixture(), 67 ).RunTestWithBp(t, bp) 68 69 m := result.ModuleForTests("foo", "android_common") 70 71 // Check AAPT2 link flags. 72 aapt2Flags := m.Output("package-res.apk").Args["flags"] 73 expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"} 74 absentFlags := android.RemoveListFromList(expectedFlags, strings.Split(aapt2Flags, " ")) 75 if len(absentFlags) > 0 { 76 t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags) 77 } 78 79 // Check overlay.list output for static_libs dependency. 80 overlayList := android.PathsRelativeToTop(m.Output("aapt2/overlay.list").Inputs) 81 staticLibPackage := "out/soong/.intermediates/bar/android_common/package-res.apk" 82 if !inList(staticLibPackage, overlayList) { 83 t.Errorf("Stactic lib res package %q missing in overlay list: %q", staticLibPackage, overlayList) 84 } 85 86 // Check AAPT2 link flags for resource_libs dependency. 87 resourceLibFlag := "-I " + "out/soong/.intermediates/baz/android_common/package-res.apk" 88 if !strings.Contains(aapt2Flags, resourceLibFlag) { 89 t.Errorf("Resource lib flag %q missing in aapt2 link flags: %q", resourceLibFlag, aapt2Flags) 90 } 91 92 // Check cert signing flags. 93 signedApk := m.Output("signed/foo.apk") 94 actualCertSigningFlags := signedApk.Args["flags"] 95 expectedCertSigningFlags := "--lineage lineage.bin --rotation-min-sdk-version 32" 96 if expectedCertSigningFlags != actualCertSigningFlags { 97 t.Errorf("Incorrect cert signing flags, expected: %q, got: %q", expectedCertSigningFlags, actualCertSigningFlags) 98 } 99 100 signingFlag := signedApk.Args["certificates"] 101 expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8" 102 if expected != signingFlag { 103 t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) 104 } 105 androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, m.Module())[0] 106 path := androidMkEntries.EntryMap["LOCAL_CERTIFICATE"] 107 expectedPath := []string{"build/make/target/product/security/platform.x509.pem"} 108 if !reflect.DeepEqual(path, expectedPath) { 109 t.Errorf("Unexpected LOCAL_CERTIFICATE value: %v, expected: %v", path, expectedPath) 110 } 111 112 // Check device location. 113 path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"] 114 expectedPath = []string{shared.JoinPath("out/target/product/test_device/product/overlay")} 115 android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", result.Config, expectedPath, path) 116 117 // A themed module has a different device location 118 m = result.ModuleForTests("foo_themed", "android_common") 119 androidMkEntries = android.AndroidMkEntriesForTest(t, result.TestContext, m.Module())[0] 120 path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"] 121 expectedPath = []string{shared.JoinPath("out/target/product/test_device/product/overlay/faza")} 122 android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", result.Config, expectedPath, path) 123 124 overrides := androidMkEntries.EntryMap["LOCAL_OVERRIDES_PACKAGES"] 125 expectedOverrides := []string{"foo"} 126 if !reflect.DeepEqual(overrides, expectedOverrides) { 127 t.Errorf("Unexpected LOCAL_OVERRIDES_PACKAGES value: %v, expected: %v", overrides, expectedOverrides) 128 } 129} 130 131func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) { 132 result := android.GroupFixturePreparers( 133 PrepareForTestWithJavaDefaultModules, 134 android.FixtureModifyConfig(android.SetKatiEnabledForTests), 135 ).RunTestWithBp(t, ` 136 java_defaults { 137 name: "rro_defaults", 138 theme: "default_theme", 139 product_specific: true, 140 aaptflags: ["--keep-raw-values"], 141 } 142 143 runtime_resource_overlay { 144 name: "foo_with_defaults", 145 defaults: ["rro_defaults"], 146 } 147 148 runtime_resource_overlay { 149 name: "foo_barebones", 150 } 151 `) 152 153 // 154 // RRO module with defaults 155 // 156 m := result.ModuleForTests("foo_with_defaults", "android_common") 157 158 // Check AAPT2 link flags. 159 aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ") 160 expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"} 161 absentFlags := android.RemoveListFromList(expectedFlags, aapt2Flags) 162 if len(absentFlags) > 0 { 163 t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags) 164 } 165 166 // Check device location. 167 path := android.AndroidMkEntriesForTest(t, result.TestContext, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] 168 expectedPath := []string{shared.JoinPath("out/target/product/test_device/product/overlay/default_theme")} 169 android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", result.Config, expectedPath, path) 170 171 // 172 // RRO module without defaults 173 // 174 m = result.ModuleForTests("foo_barebones", "android_common") 175 176 // Check AAPT2 link flags. 177 aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ") 178 unexpectedFlags := "--keep-raw-values" 179 if inList(unexpectedFlags, aapt2Flags) { 180 t.Errorf("unexpected value, %q is present in aapt2 link flags, %q", unexpectedFlags, aapt2Flags) 181 } 182 183 // Check device location. 184 path = android.AndroidMkEntriesForTest(t, result.TestContext, m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] 185 expectedPath = []string{shared.JoinPath("out/target/product/test_device/product/overlay")} 186 android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", result.Config, expectedPath, path) 187} 188 189func TestOverrideRuntimeResourceOverlay(t *testing.T) { 190 ctx, _ := testJava(t, ` 191 runtime_resource_overlay { 192 name: "foo_overlay", 193 certificate: "platform", 194 product_specific: true, 195 sdk_version: "current", 196 } 197 198 override_runtime_resource_overlay { 199 name: "bar_overlay", 200 base: "foo_overlay", 201 package_name: "com.android.bar.overlay", 202 target_package_name: "com.android.bar", 203 category: "mycategory", 204 } 205 `) 206 207 expectedVariants := []struct { 208 moduleName string 209 variantName string 210 apkPath string 211 overrides []string 212 targetVariant string 213 packageFlag string 214 targetPackageFlag string 215 categoryFlag string 216 }{ 217 { 218 variantName: "android_common", 219 apkPath: "out/soong/target/product/test_device/product/overlay/foo_overlay.apk", 220 overrides: nil, 221 targetVariant: "android_common", 222 packageFlag: "", 223 targetPackageFlag: "", 224 }, 225 { 226 variantName: "android_common_bar_overlay", 227 apkPath: "out/soong/target/product/test_device/product/overlay/bar_overlay.apk", 228 overrides: []string{"foo_overlay"}, 229 targetVariant: "android_common_bar", 230 packageFlag: "com.android.bar.overlay", 231 targetPackageFlag: "com.android.bar", 232 categoryFlag: "mycategory", 233 }, 234 } 235 for _, expected := range expectedVariants { 236 variant := ctx.ModuleForTests("foo_overlay", expected.variantName) 237 238 // Check the final apk name 239 variant.Output(expected.apkPath) 240 241 // Check if the overrides field values are correctly aggregated. 242 mod := variant.Module().(*RuntimeResourceOverlay) 243 if !reflect.DeepEqual(expected.overrides, mod.properties.Overrides) { 244 t.Errorf("Incorrect overrides property value, expected: %q, got: %q", 245 expected.overrides, mod.properties.Overrides) 246 } 247 248 // Check aapt2 flags. 249 res := variant.Output("package-res.apk") 250 aapt2Flags := res.Args["flags"] 251 checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) 252 checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", "") 253 checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag) 254 checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-category", expected.categoryFlag) 255 } 256} 257 258func TestEnforceRRO_propagatesToDependencies(t *testing.T) { 259 testCases := []struct { 260 name string 261 enforceRROTargets []string 262 rroDirs map[string][]string 263 }{ 264 { 265 name: "no RRO", 266 enforceRROTargets: nil, 267 rroDirs: map[string][]string{ 268 "foo": nil, 269 "bar": nil, 270 }, 271 }, 272 { 273 name: "enforce RRO on all", 274 enforceRROTargets: []string{"*"}, 275 rroDirs: map[string][]string{ 276 "foo": {"product/vendor/blah/overlay/lib2/res"}, 277 "bar": {"product/vendor/blah/overlay/lib2/res"}, 278 }, 279 }, 280 { 281 name: "enforce RRO on foo", 282 enforceRROTargets: []string{"foo"}, 283 rroDirs: map[string][]string{ 284 "foo": {"product/vendor/blah/overlay/lib2/res"}, 285 "bar": {"product/vendor/blah/overlay/lib2/res"}, 286 }, 287 }, 288 } 289 290 productResourceOverlays := []string{ 291 "product/vendor/blah/overlay", 292 } 293 294 fs := android.MockFS{ 295 "lib2/res/values/strings.xml": nil, 296 "product/vendor/blah/overlay/lib2/res/values/strings.xml": nil, 297 } 298 299 bp := ` 300 android_app { 301 name: "foo", 302 sdk_version: "current", 303 resource_dirs: [], 304 static_libs: ["lib"], 305 } 306 307 android_app { 308 name: "bar", 309 sdk_version: "current", 310 resource_dirs: [], 311 static_libs: ["lib"], 312 } 313 314 android_library { 315 name: "lib", 316 sdk_version: "current", 317 resource_dirs: [], 318 static_libs: ["lib2"], 319 } 320 321 android_library { 322 name: "lib2", 323 sdk_version: "current", 324 resource_dirs: ["lib2/res"], 325 } 326 ` 327 328 for _, testCase := range testCases { 329 t.Run(testCase.name, func(t *testing.T) { 330 result := android.GroupFixturePreparers( 331 PrepareForTestWithJavaDefaultModules, 332 fs.AddToFixture(), 333 android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { 334 variables.ProductResourceOverlays = productResourceOverlays 335 if testCase.enforceRROTargets != nil { 336 variables.EnforceRROTargets = testCase.enforceRROTargets 337 } 338 }), 339 ).RunTestWithBp(t, bp) 340 341 modules := []string{"foo", "bar"} 342 for _, moduleName := range modules { 343 module := result.ModuleForTests(moduleName, "android_common") 344 mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0] 345 actualRRODirs := mkEntries.EntryMap["LOCAL_SOONG_PRODUCT_RRO_DIRS"] 346 if !reflect.DeepEqual(actualRRODirs, testCase.rroDirs[moduleName]) { 347 t.Errorf("exected %s LOCAL_SOONG_PRODUCT_RRO_DIRS entry: %v\ngot:%q", 348 moduleName, testCase.rroDirs[moduleName], actualRRODirs) 349 } 350 } 351 }) 352 } 353} 354 355func TestRuntimeResourceOverlayPartition(t *testing.T) { 356 bp := ` 357 runtime_resource_overlay { 358 name: "device_specific", 359 device_specific: true, 360 } 361 runtime_resource_overlay { 362 name: "soc_specific", 363 soc_specific: true, 364 } 365 runtime_resource_overlay { 366 name: "system_ext_specific", 367 system_ext_specific: true, 368 } 369 runtime_resource_overlay { 370 name: "product_specific", 371 product_specific: true, 372 } 373 runtime_resource_overlay { 374 name: "default" 375 } 376 ` 377 testCases := []struct { 378 name string 379 expectedPath string 380 }{ 381 { 382 name: "device_specific", 383 expectedPath: "out/soong/target/product/test_device/odm/overlay", 384 }, 385 { 386 name: "soc_specific", 387 expectedPath: "out/soong/target/product/test_device/vendor/overlay", 388 }, 389 { 390 name: "system_ext_specific", 391 expectedPath: "out/soong/target/product/test_device/system_ext/overlay", 392 }, 393 { 394 name: "product_specific", 395 expectedPath: "out/soong/target/product/test_device/product/overlay", 396 }, 397 { 398 name: "default", 399 expectedPath: "out/soong/target/product/test_device/product/overlay", 400 }, 401 } 402 for _, testCase := range testCases { 403 ctx, _ := testJava(t, bp) 404 mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*RuntimeResourceOverlay) 405 android.AssertPathRelativeToTopEquals(t, "Install dir is not correct for "+testCase.name, testCase.expectedPath, mod.installDir) 406 } 407} 408 409func TestRuntimeResourceOverlayFlagsPackages(t *testing.T) { 410 result := android.GroupFixturePreparers( 411 prepareForJavaTest, 412 ).RunTestWithBp(t, ` 413 runtime_resource_overlay { 414 name: "foo", 415 sdk_version: "current", 416 flags_packages: [ 417 "bar", 418 "baz", 419 ], 420 } 421 aconfig_declarations { 422 name: "bar", 423 package: "com.example.package.bar", 424 container: "com.android.foo", 425 srcs: [ 426 "bar.aconfig", 427 ], 428 } 429 aconfig_declarations { 430 name: "baz", 431 package: "com.example.package.baz", 432 container: "com.android.foo", 433 srcs: [ 434 "baz.aconfig", 435 ], 436 } 437 `) 438 439 foo := result.ModuleForTests("foo", "android_common") 440 441 // runtime_resource_overlay module depends on aconfig_declarations listed in flags_packages 442 android.AssertBoolEquals(t, "foo expected to depend on bar", true, 443 CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar")) 444 445 android.AssertBoolEquals(t, "foo expected to depend on baz", true, 446 CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "baz")) 447 448 aapt2LinkRule := foo.Rule("android/soong/java.aapt2Link") 449 linkInFlags := aapt2LinkRule.Args["inFlags"] 450 android.AssertStringDoesContain(t, 451 "aapt2 link command expected to pass feature flags arguments", 452 linkInFlags, 453 "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", 454 ) 455} 456