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