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 return 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} 52 53func testPlatformSystemServerModuleConfig(ctx android.PathContext, name string) *ModuleConfig { 54 return createTestModuleConfig( 55 name, 56 fmt.Sprintf("/system/framework/%s.jar", name), 57 android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)), 58 android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)), 59 android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name))) 60} 61 62func testSystemExtSystemServerModuleConfig(ctx android.PathContext, name string) *ModuleConfig { 63 return createTestModuleConfig( 64 name, 65 fmt.Sprintf("/system_ext/framework/%s.jar", name), 66 android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)), 67 android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)), 68 android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name))) 69} 70 71func createTestModuleConfig(name, dexLocation string, buildPath, dexPath, enforceUsesLibrariesStatusFile android.OutputPath) *ModuleConfig { 72 return &ModuleConfig{ 73 Name: name, 74 DexLocation: dexLocation, 75 BuildPath: buildPath, 76 DexPath: dexPath, 77 UncompressedDex: false, 78 HasApkLibraries: false, 79 PreoptFlags: nil, 80 ProfileClassListing: android.OptionalPath{}, 81 ProfileIsTextListing: false, 82 EnforceUsesLibrariesStatusFile: enforceUsesLibrariesStatusFile, 83 EnforceUsesLibraries: false, 84 ClassLoaderContexts: nil, 85 Archs: []android.ArchType{android.Arm}, 86 DexPreoptImagesDeps: []android.OutputPaths{android.OutputPaths{}}, 87 DexPreoptImageLocationsOnHost: []string{}, 88 PreoptBootClassPathDexFiles: nil, 89 PreoptBootClassPathDexLocations: nil, 90 PreoptExtractedApk: false, 91 NoCreateAppImage: false, 92 ForceCreateAppImage: false, 93 PresignedPrebuilt: false, 94 } 95} 96 97func TestDexPreopt(t *testing.T) { 98 config := android.TestConfig("out", nil, "", nil) 99 ctx := android.BuilderContextForTesting(config) 100 globalSoong := globalSoongConfigForTests() 101 global := GlobalConfigForTests(ctx) 102 module := testSystemModuleConfig(ctx, "test") 103 104 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module) 105 if err != nil { 106 t.Fatal(err) 107 } 108 109 wantInstalls := android.RuleBuilderInstalls{ 110 {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, 111 {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, 112 } 113 114 if rule.Installs().String() != wantInstalls.String() { 115 t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) 116 } 117} 118 119func TestDexPreoptSystemOther(t *testing.T) { 120 config := android.TestConfig("out", nil, "", nil) 121 ctx := android.BuilderContextForTesting(config) 122 globalSoong := globalSoongConfigForTests() 123 global := GlobalConfigForTests(ctx) 124 systemModule := testSystemModuleConfig(ctx, "Stest") 125 systemProductModule := testSystemProductModuleConfig(ctx, "SPtest") 126 productModule := testProductModuleConfig(ctx, "Ptest") 127 128 global.HasSystemOther = true 129 130 type moduleTest struct { 131 module *ModuleConfig 132 expectedPartition string 133 } 134 tests := []struct { 135 patterns []string 136 moduleTests []moduleTest 137 }{ 138 { 139 patterns: []string{"app/%"}, 140 moduleTests: []moduleTest{ 141 {module: systemModule, expectedPartition: "system_other/system"}, 142 {module: systemProductModule, expectedPartition: "system/product"}, 143 {module: productModule, expectedPartition: "product"}, 144 }, 145 }, 146 // product/app/% only applies to product apps inside the system partition 147 { 148 patterns: []string{"app/%", "product/app/%"}, 149 moduleTests: []moduleTest{ 150 {module: systemModule, expectedPartition: "system_other/system"}, 151 {module: systemProductModule, expectedPartition: "system_other/system/product"}, 152 {module: productModule, expectedPartition: "product"}, 153 }, 154 }, 155 } 156 157 for _, test := range tests { 158 global.PatternsOnSystemOther = test.patterns 159 for _, mt := range test.moduleTests { 160 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module) 161 if err != nil { 162 t.Fatal(err) 163 } 164 165 name := mt.module.Name 166 wantInstalls := android.RuleBuilderInstalls{ 167 {android.PathForOutput(ctx, name+"/oat/arm/package.odex"), fmt.Sprintf("/%s/app/test/oat/arm/%s.odex", mt.expectedPartition, name)}, 168 {android.PathForOutput(ctx, name+"/oat/arm/package.vdex"), fmt.Sprintf("/%s/app/test/oat/arm/%s.vdex", mt.expectedPartition, name)}, 169 } 170 171 if rule.Installs().String() != wantInstalls.String() { 172 t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) 173 } 174 } 175 } 176 177} 178 179func TestDexPreoptApexSystemServerJars(t *testing.T) { 180 config := android.TestConfig("out", nil, "", nil) 181 ctx := android.BuilderContextForTesting(config) 182 globalSoong := globalSoongConfigForTests() 183 global := GlobalConfigForTests(ctx) 184 module := testApexModuleConfig(ctx, "service-A", "com.android.apex1") 185 186 global.ApexSystemServerJars = android.CreateTestConfiguredJarList( 187 []string{"com.android.apex1:service-A"}) 188 189 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module) 190 if err != nil { 191 t.Fatal(err) 192 } 193 194 wantInstalls := android.RuleBuilderInstalls{ 195 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.odex"}, 196 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.vdex"}, 197 } 198 199 android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) 200} 201 202func TestDexPreoptStandaloneSystemServerJars(t *testing.T) { 203 config := android.TestConfig("out", nil, "", nil) 204 ctx := android.BuilderContextForTesting(config) 205 globalSoong := globalSoongConfigForTests() 206 global := GlobalConfigForTests(ctx) 207 module := testPlatformSystemServerModuleConfig(ctx, "service-A") 208 209 global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList( 210 []string{"platform:service-A"}) 211 212 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module) 213 if err != nil { 214 t.Fatal(err) 215 } 216 217 wantInstalls := android.RuleBuilderInstalls{ 218 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/service-A.odex"}, 219 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/service-A.vdex"}, 220 } 221 222 android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) 223} 224 225func TestDexPreoptSystemExtSystemServerJars(t *testing.T) { 226 config := android.TestConfig("out", nil, "", nil) 227 ctx := android.BuilderContextForTesting(config) 228 globalSoong := globalSoongConfigForTests() 229 global := GlobalConfigForTests(ctx) 230 module := testSystemExtSystemServerModuleConfig(ctx, "service-A") 231 232 global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList( 233 []string{"system_ext:service-A"}) 234 235 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module) 236 if err != nil { 237 t.Fatal(err) 238 } 239 240 wantInstalls := android.RuleBuilderInstalls{ 241 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system_ext/framework/oat/arm/service-A.odex"}, 242 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system_ext/framework/oat/arm/service-A.vdex"}, 243 } 244 245 android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) 246} 247 248func TestDexPreoptApexStandaloneSystemServerJars(t *testing.T) { 249 config := android.TestConfig("out", nil, "", nil) 250 ctx := android.BuilderContextForTesting(config) 251 globalSoong := globalSoongConfigForTests() 252 global := GlobalConfigForTests(ctx) 253 module := testApexModuleConfig(ctx, "service-A", "com.android.apex1") 254 255 global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList( 256 []string{"com.android.apex1:service-A"}) 257 258 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module) 259 if err != nil { 260 t.Fatal(err) 261 } 262 263 wantInstalls := android.RuleBuilderInstalls{ 264 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.odex"}, 265 {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.vdex"}, 266 } 267 268 android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) 269} 270 271func TestDexPreoptProfile(t *testing.T) { 272 config := android.TestConfig("out", nil, "", nil) 273 ctx := android.BuilderContextForTesting(config) 274 globalSoong := globalSoongConfigForTests() 275 global := GlobalConfigForTests(ctx) 276 module := testSystemModuleConfig(ctx, "test") 277 278 module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile")) 279 280 rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module) 281 if err != nil { 282 t.Fatal(err) 283 } 284 285 wantInstalls := android.RuleBuilderInstalls{ 286 {android.PathForOutput(ctx, "test/profile.prof"), "/system/app/test/test.apk.prof"}, 287 {android.PathForOutput(ctx, "test/oat/arm/package.art"), "/system/app/test/oat/arm/test.art"}, 288 {android.PathForOutput(ctx, "test/oat/arm/package.odex"), "/system/app/test/oat/arm/test.odex"}, 289 {android.PathForOutput(ctx, "test/oat/arm/package.vdex"), "/system/app/test/oat/arm/test.vdex"}, 290 } 291 292 if rule.Installs().String() != wantInstalls.String() { 293 t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs()) 294 } 295} 296 297func TestDexPreoptConfigToJson(t *testing.T) { 298 config := android.TestConfig("out", nil, "", nil) 299 ctx := android.BuilderContextForTesting(config) 300 module := testSystemModuleConfig(ctx, "test") 301 data, err := moduleConfigToJSON(module) 302 if err != nil { 303 t.Errorf("Failed to convert module config data to JSON, %v", err) 304 } 305 parsed, err := ParseModuleConfig(ctx, data) 306 if err != nil { 307 t.Errorf("Failed to parse JSON, %v", err) 308 } 309 before := fmt.Sprintf("%v", module) 310 after := fmt.Sprintf("%v", parsed) 311 android.AssertStringEquals(t, "The result must be the same as the original after marshalling and unmarshalling it.", before, after) 312} 313