1// Copyright 2018 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 dexpreopt 16 17import ( 18 "android/soong/android" 19 "fmt" 20 "testing" 21) 22 23func testSystemModuleConfig(ctx android.PathContext, name string) *ModuleConfig { 24 return testModuleConfig(ctx, name, "system") 25} 26 27func testSystemProductModuleConfig(ctx android.PathContext, name string) *ModuleConfig { 28 return testModuleConfig(ctx, name, "system/product") 29} 30 31func testProductModuleConfig(ctx android.PathContext, name string) *ModuleConfig { 32 return testModuleConfig(ctx, name, "product") 33} 34 35func testModuleConfig(ctx android.PathContext, name, partition string) *ModuleConfig { 36 return createTestModuleConfig( 37 name, 38 fmt.Sprintf("/%s/app/test/%s.apk", partition, name), 39 android.PathForOutput(ctx, fmt.Sprintf("%s/%s.apk", name, name)), 40 android.PathForOutput(ctx, fmt.Sprintf("%s/dex/%s.jar", name, name)), 41 android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name))) 42} 43 44func testApexModuleConfig(ctx android.PathContext, name, apexName string) *ModuleConfig { 45 ret := createTestModuleConfig( 46 name, 47 fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, name), 48 android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)), 49 android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)), 50 android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name))) 51 ret.ApexPartition = "/system" 52 return ret 53} 54 55func testPlatformSystemServerModuleConfig(ctx android.PathContext, name string) *ModuleConfig { 56 return createTestModuleConfig( 57 name, 58 fmt.Sprintf("/system/framework/%s.jar", name), 59 android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)), 60 android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)), 61 android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name))) 62} 63 64func testSystemExtSystemServerModuleConfig(ctx android.PathContext, name string) *ModuleConfig { 65 return createTestModuleConfig( 66 name, 67 fmt.Sprintf("/system_ext/framework/%s.jar", name), 68 android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)), 69 android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)), 70 android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name))) 71} 72 73func createTestModuleConfig(name, dexLocation string, buildPath, dexPath, enforceUsesLibrariesStatusFile android.OutputPath) *ModuleConfig { 74 return &ModuleConfig{ 75 Name: name, 76 DexLocation: dexLocation, 77 BuildPath: buildPath, 78 DexPath: dexPath, 79 UncompressedDex: false, 80 HasApkLibraries: false, 81 PreoptFlags: nil, 82 ProfileClassListing: android.OptionalPath{}, 83 ProfileIsTextListing: false, 84 EnforceUsesLibrariesStatusFile: enforceUsesLibrariesStatusFile, 85 EnforceUsesLibraries: false, 86 ClassLoaderContexts: nil, 87 Archs: []android.ArchType{android.Arm}, 88 DexPreoptImagesDeps: []android.OutputPaths{android.OutputPaths{}}, 89 DexPreoptImageLocationsOnHost: []string{}, 90 PreoptBootClassPathDexFiles: nil, 91 PreoptBootClassPathDexLocations: nil, 92 NoCreateAppImage: false, 93 ForceCreateAppImage: false, 94 PresignedPrebuilt: false, 95 } 96} 97 98func TestDexPreopt(t *testing.T) { 99 config := android.TestConfig("out", nil, "", nil) 100 ctx := android.BuilderContextForTesting(config) 101 globalSoong := globalSoongConfigForTests(ctx) 102 global := GlobalConfigForTests(ctx) 103 module := testSystemModuleConfig(ctx, "test") 104 productPackages := android.PathForTesting("product_packages.txt") 105 106 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) 107 if err != nil { 108 t.Fatal(err) 109 } 110 111 wantInstalls := android.RuleBuilderInstalls{ 112 {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, 113 {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, 114 } 115 116 if rule.Installs().String() != wantInstalls.String() { 117 t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) 118 } 119 120 android.AssertStringListContains(t, "", rule.Inputs().RelativeToTop().Strings(), 121 "out/soong/dexpreopt_test/uffd_gc_flag.txt") 122} 123 124func TestDexPreoptSystemOther(t *testing.T) { 125 config := android.TestConfig("out", nil, "", nil) 126 ctx := android.BuilderContextForTesting(config) 127 globalSoong := globalSoongConfigForTests(ctx) 128 global := GlobalConfigForTests(ctx) 129 systemModule := testSystemModuleConfig(ctx, "Stest") 130 systemProductModule := testSystemProductModuleConfig(ctx, "SPtest") 131 productModule := testProductModuleConfig(ctx, "Ptest") 132 productPackages := android.PathForTesting("product_packages.txt") 133 134 global.HasSystemOther = true 135 136 type moduleTest struct { 137 module *ModuleConfig 138 expectedPartition string 139 } 140 tests := []struct { 141 patterns []string 142 moduleTests []moduleTest 143 }{ 144 { 145 patterns: []string{"app/%"}, 146 moduleTests: []moduleTest{ 147 {module: systemModule, expectedPartition: "system_other/system"}, 148 {module: systemProductModule, expectedPartition: "system/product"}, 149 {module: productModule, expectedPartition: "product"}, 150 }, 151 }, 152 // product/app/% only applies to product apps inside the system partition 153 { 154 patterns: []string{"app/%", "product/app/%"}, 155 moduleTests: []moduleTest{ 156 {module: systemModule, expectedPartition: "system_other/system"}, 157 {module: systemProductModule, expectedPartition: "system_other/system/product"}, 158 {module: productModule, expectedPartition: "system_other/product"}, 159 }, 160 }, 161 } 162 163 for _, test := range tests { 164 global.PatternsOnSystemOther = test.patterns 165 for _, mt := range test.moduleTests { 166 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module, productPackages, true) 167 if err != nil { 168 t.Fatal(err) 169 } 170 171 name := mt.module.Name 172 wantInstalls := android.RuleBuilderInstalls{ 173 {android.PathForOutput(ctx, name+"/oat/arm/package.odex"), fmt.Sprintf("/%s/app/test/oat/arm/%s.odex", mt.expectedPartition, name)}, 174 {android.PathForOutput(ctx, name+"/oat/arm/package.vdex"), fmt.Sprintf("/%s/app/test/oat/arm/%s.vdex", mt.expectedPartition, name)}, 175 } 176 177 if rule.Installs().String() != wantInstalls.String() { 178 t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) 179 } 180 } 181 } 182 183} 184 185func TestDexPreoptApexSystemServerJars(t *testing.T) { 186 // modify the global variable for test 187 var oldDexpreoptRunningInSoong = DexpreoptRunningInSoong 188 DexpreoptRunningInSoong = true 189 190 // test begin 191 config := android.TestConfig("out", nil, "", nil) 192 ctx := android.BuilderContextForTesting(config) 193 globalSoong := globalSoongConfigForTests(ctx) 194 global := GlobalConfigForTests(ctx) 195 module := testApexModuleConfig(ctx, "service-A", "com.android.apex1") 196 productPackages := android.PathForTesting("product_packages.txt") 197 198 global.ApexSystemServerJars = android.CreateTestConfiguredJarList( 199 []string{"com.android.apex1:service-A"}) 200 201 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) 202 if err != nil { 203 t.Fatal(err) 204 } 205 206 wantInstalls := android.RuleBuilderInstalls{ 207 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/apex@com.android.apex1@[email protected]@classes.odex"}, 208 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/apex@com.android.apex1@[email protected]@classes.vdex"}, 209 } 210 211 android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) 212 213 android.AssertStringListContains(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar") 214 215 // rule with apex sscp cp as false 216 rule, err = GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, false) 217 if err != nil { 218 t.Fatal(err) 219 } 220 android.AssertStringListDoesNotContain(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar") 221 222 // cleanup the global variable for test 223 DexpreoptRunningInSoong = oldDexpreoptRunningInSoong 224} 225 226// Same as `TestDexPreoptApexSystemServerJars`, but the apex jar is in /system_ext 227func TestDexPreoptApexSystemServerJarsSystemExt(t *testing.T) { 228 // modify the global variable for test 229 var oldDexpreoptRunningInSoong = DexpreoptRunningInSoong 230 DexpreoptRunningInSoong = true 231 232 // test begin 233 config := android.TestConfig("out", nil, "", nil) 234 ctx := android.BuilderContextForTesting(config) 235 globalSoong := globalSoongConfigForTests(ctx) 236 global := GlobalConfigForTests(ctx) 237 module := testApexModuleConfig(ctx, "service-A", "com.android.apex1") 238 module.ApexPartition = "/system_ext" 239 productPackages := android.PathForTesting("product_packages.txt") 240 241 global.ApexSystemServerJars = android.CreateTestConfiguredJarList( 242 []string{"com.android.apex1:service-A"}) 243 244 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) 245 if err != nil { 246 t.Fatal(err) 247 } 248 249 wantInstalls := android.RuleBuilderInstalls{ 250 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system_ext/framework/oat/arm/apex@com.android.apex1@[email protected]@classes.odex"}, 251 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system_ext/framework/oat/arm/apex@com.android.apex1@[email protected]@classes.vdex"}, 252 } 253 254 android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) 255 256 android.AssertStringListContains(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar") 257 258 // rule with apex sscp cp as false 259 rule, err = GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, false) 260 if err != nil { 261 t.Fatal(err) 262 } 263 android.AssertStringListDoesNotContain(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar") 264 265 // cleanup the global variable for test 266 DexpreoptRunningInSoong = oldDexpreoptRunningInSoong 267} 268 269func TestDexPreoptStandaloneSystemServerJars(t *testing.T) { 270 config := android.TestConfig("out", nil, "", nil) 271 ctx := android.BuilderContextForTesting(config) 272 globalSoong := globalSoongConfigForTests(ctx) 273 global := GlobalConfigForTests(ctx) 274 module := testPlatformSystemServerModuleConfig(ctx, "service-A") 275 productPackages := android.PathForTesting("product_packages.txt") 276 277 global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList( 278 []string{"platform:service-A"}) 279 280 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) 281 if err != nil { 282 t.Fatal(err) 283 } 284 285 wantInstalls := android.RuleBuilderInstalls{ 286 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/service-A.odex"}, 287 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/service-A.vdex"}, 288 } 289 290 android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) 291} 292 293func TestDexPreoptSystemExtSystemServerJars(t *testing.T) { 294 config := android.TestConfig("out", nil, "", nil) 295 ctx := android.BuilderContextForTesting(config) 296 globalSoong := globalSoongConfigForTests(ctx) 297 global := GlobalConfigForTests(ctx) 298 module := testSystemExtSystemServerModuleConfig(ctx, "service-A") 299 productPackages := android.PathForTesting("product_packages.txt") 300 301 global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList( 302 []string{"system_ext:service-A"}) 303 304 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) 305 if err != nil { 306 t.Fatal(err) 307 } 308 309 wantInstalls := android.RuleBuilderInstalls{ 310 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system_ext/framework/oat/arm/service-A.odex"}, 311 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system_ext/framework/oat/arm/service-A.vdex"}, 312 } 313 314 android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) 315} 316 317func TestDexPreoptApexStandaloneSystemServerJars(t *testing.T) { 318 config := android.TestConfig("out", nil, "", nil) 319 ctx := android.BuilderContextForTesting(config) 320 globalSoong := globalSoongConfigForTests(ctx) 321 global := GlobalConfigForTests(ctx) 322 module := testApexModuleConfig(ctx, "service-A", "com.android.apex1") 323 productPackages := android.PathForTesting("product_packages.txt") 324 325 global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList( 326 []string{"com.android.apex1:service-A"}) 327 328 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) 329 if err != nil { 330 t.Fatal(err) 331 } 332 333 wantInstalls := android.RuleBuilderInstalls{ 334 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/apex@com.android.apex1@[email protected]@classes.odex"}, 335 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/apex@com.android.apex1@[email protected]@classes.vdex"}, 336 } 337 338 android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) 339} 340 341func TestDexPreoptProfile(t *testing.T) { 342 config := android.TestConfig("out", nil, "", nil) 343 ctx := android.BuilderContextForTesting(config) 344 globalSoong := globalSoongConfigForTests(ctx) 345 global := GlobalConfigForTests(ctx) 346 module := testSystemModuleConfig(ctx, "test") 347 productPackages := android.PathForTesting("product_packages.txt") 348 349 module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile")) 350 351 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) 352 if err != nil { 353 t.Fatal(err) 354 } 355 356 wantInstalls := android.RuleBuilderInstalls{ 357 {android.PathForOutput(ctx, "test/profile.prof"), "/system/app/test/test.apk.prof"}, 358 {android.PathForOutput(ctx, "test/oat/arm/package.art"), "/system/app/test/oat/arm/test.art"}, 359 {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, 360 {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, 361 } 362 363 if rule.Installs().String() != wantInstalls.String() { 364 t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) 365 } 366} 367 368func TestDexPreoptConfigToJson(t *testing.T) { 369 config := android.TestConfig("out", nil, "", nil) 370 ctx := android.BuilderContextForTesting(config) 371 module := testSystemModuleConfig(ctx, "test") 372 data, err := moduleConfigToJSON(module) 373 if err != nil { 374 t.Errorf("Failed to convert module config data to JSON, %v", err) 375 } 376 parsed, err := ParseModuleConfig(ctx, data) 377 if err != nil { 378 t.Errorf("Failed to parse JSON, %v", err) 379 } 380 before := fmt.Sprintf("%v", module) 381 after := fmt.Sprintf("%v", parsed) 382 android.AssertStringEquals(t, "The result must be the same as the original after marshalling and unmarshalling it.", before, after) 383} 384 385func TestUffdGcFlagForce(t *testing.T) { 386 for _, enableUffdGc := range []string{"true", "false"} { 387 t.Run(enableUffdGc, func(t *testing.T) { 388 preparers := android.GroupFixturePreparers( 389 PrepareForTestWithFakeDex2oatd, 390 PrepareForTestWithDexpreoptConfig, 391 FixtureSetEnableUffdGc(enableUffdGc), 392 ) 393 394 result := preparers.RunTest(t) 395 ctx := result.TestContext 396 397 ctx.SingletonForTests("dexpreopt-soong-config").Output("out/soong/dexpreopt/uffd_gc_flag.txt") 398 }) 399 } 400} 401 402func TestUffdGcFlagDefault(t *testing.T) { 403 preparers := android.GroupFixturePreparers( 404 PrepareForTestWithFakeDex2oatd, 405 PrepareForTestWithDexpreoptConfig, 406 FixtureSetEnableUffdGc("default"), 407 ) 408 409 result := preparers.RunTest(t) 410 ctx := result.TestContext 411 config := ctx.Config() 412 413 rule := ctx.SingletonForTests("dexpreopt-soong-config").Rule("dexpreopt_uffd_gc_flag") 414 415 android.AssertStringDoesContain(t, "", rule.RuleParams.Command, "construct_uffd_gc_flag") 416 android.AssertStringPathsRelativeToTopEquals(t, "", config, []string{ 417 "out/soong/dexpreopt/uffd_gc_flag.txt", 418 }, rule.AllOutputs()) 419 android.AssertPathsRelativeToTopEquals(t, "", []string{ 420 "out/soong/dexpreopt/kernel_version_for_uffd_gc.txt", 421 }, rule.Implicits) 422} 423 424func TestUffdGcFlagBogus(t *testing.T) { 425 preparers := android.GroupFixturePreparers( 426 PrepareForTestWithFakeDex2oatd, 427 PrepareForTestWithDexpreoptConfig, 428 FixtureSetEnableUffdGc("bogus"), 429 ) 430 431 preparers. 432 ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( 433 "Unknown value of PRODUCT_ENABLE_UFFD_GC: bogus")). 434 RunTest(t) 435} 436