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 "fmt" 19 "path/filepath" 20 "testing" 21 22 "android/soong/android" 23 "github.com/google/blueprint/proptools" 24) 25 26// TODO(b/177892522): Move these tests into a more appropriate place. 27 28func fixtureSetPrebuiltHiddenApiDirProductVariable(prebuiltHiddenApiDir *string) android.FixturePreparer { 29 return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { 30 variables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir 31 }) 32} 33 34var prepareForTestWithDefaultPlatformBootclasspath = android.FixtureAddTextFile("frameworks/base/boot/Android.bp", ` 35 platform_bootclasspath { 36 name: "platform-bootclasspath", 37 } 38`) 39 40var hiddenApiFixtureFactory = android.GroupFixturePreparers( 41 prepareForJavaTest, PrepareForTestWithHiddenApiBuildComponents) 42 43func TestHiddenAPISingleton(t *testing.T) { 44 result := android.GroupFixturePreparers( 45 hiddenApiFixtureFactory, 46 FixtureConfigureBootJars("platform:foo"), 47 prepareForTestWithDefaultPlatformBootclasspath, 48 ).RunTestWithBp(t, ` 49 java_library { 50 name: "foo", 51 srcs: ["a.java"], 52 compile_dex: true, 53 } 54 `) 55 56 hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") 57 hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") 58 want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" 59 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) 60} 61 62func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) { 63 expectedErrorMessage := "module prebuilt_foo{os:android,arch:common} does not provide a dex jar" 64 65 android.GroupFixturePreparers( 66 hiddenApiFixtureFactory, 67 FixtureConfigureBootJars("platform:foo"), 68 prepareForTestWithDefaultPlatformBootclasspath, 69 ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorMessage)). 70 RunTestWithBp(t, ` 71 java_library { 72 name: "foo", 73 srcs: ["a.java"], 74 compile_dex: true, 75 } 76 77 java_import { 78 name: "foo", 79 jars: ["a.jar"], 80 prefer: true, 81 } 82 `) 83} 84 85func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { 86 result := android.GroupFixturePreparers( 87 hiddenApiFixtureFactory, 88 FixtureConfigureBootJars("platform:foo"), 89 prepareForTestWithDefaultPlatformBootclasspath, 90 ).RunTestWithBp(t, ` 91 java_import { 92 name: "foo", 93 jars: ["a.jar"], 94 compile_dex: true, 95 } 96 `) 97 98 hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") 99 hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") 100 want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" 101 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) 102} 103 104func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { 105 result := android.GroupFixturePreparers( 106 hiddenApiFixtureFactory, 107 FixtureConfigureBootJars("platform:foo"), 108 prepareForTestWithDefaultPlatformBootclasspath, 109 ).RunTestWithBp(t, ` 110 java_library { 111 name: "foo", 112 srcs: ["a.java"], 113 compile_dex: true, 114 } 115 116 java_import { 117 name: "foo", 118 jars: ["a.jar"], 119 compile_dex: true, 120 prefer: false, 121 } 122 `) 123 124 hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") 125 hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") 126 fromSourceJarArg := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" 127 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, fromSourceJarArg) 128 129 prebuiltJarArg := "--boot-dex=out/soong/.intermediates/foo/android_common/dex/foo.jar" 130 android.AssertStringDoesNotContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, prebuiltJarArg) 131} 132 133func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { 134 result := android.GroupFixturePreparers( 135 hiddenApiFixtureFactory, 136 FixtureConfigureBootJars("platform:foo"), 137 prepareForTestWithDefaultPlatformBootclasspath, 138 ).RunTestWithBp(t, ` 139 java_library { 140 name: "foo", 141 srcs: ["a.java"], 142 compile_dex: true, 143 } 144 145 java_import { 146 name: "foo", 147 jars: ["a.jar"], 148 compile_dex: true, 149 prefer: true, 150 } 151 `) 152 153 hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") 154 hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") 155 prebuiltJarArg := "--boot-dex=out/soong/.intermediates/prebuilt_foo/android_common/dex/foo.jar" 156 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, prebuiltJarArg) 157 158 fromSourceJarArg := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" 159 android.AssertStringDoesNotContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, fromSourceJarArg) 160} 161 162func TestHiddenAPISingletonSdks(t *testing.T) { 163 testCases := []struct { 164 name string 165 unbundledBuild bool 166 publicStub string 167 systemStub string 168 testStub string 169 corePlatformStub string 170 171 // Additional test preparer 172 preparer android.FixturePreparer 173 }{ 174 { 175 name: "testBundled", 176 unbundledBuild: false, 177 publicStub: "android_stubs_current", 178 systemStub: "android_system_stubs_current", 179 testStub: "android_test_stubs_current", 180 corePlatformStub: "legacy.core.platform.api.stubs", 181 preparer: android.GroupFixturePreparers(), 182 }, { 183 name: "testUnbundled", 184 unbundledBuild: true, 185 publicStub: "sdk_public_current_android", 186 systemStub: "sdk_system_current_android", 187 testStub: "sdk_test_current_android", 188 corePlatformStub: "legacy.core.platform.api.stubs", 189 preparer: PrepareForTestWithPrebuiltsOfCurrentApi, 190 }, 191 } 192 for _, tc := range testCases { 193 t.Run(tc.name, func(t *testing.T) { 194 result := android.GroupFixturePreparers( 195 hiddenApiFixtureFactory, 196 tc.preparer, 197 prepareForTestWithDefaultPlatformBootclasspath, 198 android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { 199 variables.Always_use_prebuilt_sdks = proptools.BoolPtr(tc.unbundledBuild) 200 }), 201 ).RunTest(t) 202 203 hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") 204 hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") 205 wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild) 206 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantPublicStubs) 207 208 wantSystemStubs := "--system-stub-classpath=" + generateSdkDexPath(tc.systemStub, tc.unbundledBuild) 209 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantSystemStubs) 210 211 wantTestStubs := "--test-stub-classpath=" + generateSdkDexPath(tc.testStub, tc.unbundledBuild) 212 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantTestStubs) 213 214 wantCorePlatformStubs := "--core-platform-stub-classpath=" + generateDexPath(defaultJavaDir, tc.corePlatformStub) 215 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantCorePlatformStubs) 216 }) 217 } 218} 219 220func generateDexedPath(subDir, dex, module string) string { 221 return fmt.Sprintf("out/soong/.intermediates/%s/android_common/%s/%s.jar", subDir, dex, module) 222} 223 224func generateDexPath(moduleDir string, module string) string { 225 return generateDexedPath(filepath.Join(moduleDir, module), "dex", module) 226} 227 228func generateSdkDexPath(module string, unbundled bool) string { 229 if unbundled { 230 return generateDexedPath("prebuilts/sdk/"+module, "dex", module) 231 } 232 return generateDexPath(defaultJavaDir, module) 233} 234 235func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { 236 237 // The idea behind this test is to ensure that when the build is 238 // confugured with a PrebuiltHiddenApiDir that the rules for the 239 // hiddenapi singleton copy the prebuilts to the typical output 240 // location, and then use that output location for the hiddenapi encode 241 // dex step. 242 243 // Where to find the prebuilt hiddenapi files: 244 prebuiltHiddenApiDir := "path/to/prebuilt/hiddenapi" 245 246 result := android.GroupFixturePreparers( 247 hiddenApiFixtureFactory, 248 FixtureConfigureBootJars("platform:foo"), 249 fixtureSetPrebuiltHiddenApiDirProductVariable(&prebuiltHiddenApiDir), 250 ).RunTestWithBp(t, ` 251 java_import { 252 name: "foo", 253 jars: ["a.jar"], 254 compile_dex: true, 255 } 256 `) 257 258 expectedCpInput := prebuiltHiddenApiDir + "/hiddenapi-flags.csv" 259 expectedCpOutput := "out/soong/hiddenapi/hiddenapi-flags.csv" 260 expectedFlagsCsv := "out/soong/hiddenapi/hiddenapi-flags.csv" 261 262 foo := result.ModuleForTests("foo", "android_common") 263 264 hiddenAPI := result.SingletonForTests("hiddenapi") 265 cpRule := hiddenAPI.Rule("Cp") 266 actualCpInput := cpRule.BuildParams.Input 267 actualCpOutput := cpRule.BuildParams.Output 268 encodeDexRule := foo.Rule("hiddenAPIEncodeDex") 269 actualFlagsCsv := encodeDexRule.BuildParams.Args["flagsCsv"] 270 271 android.AssertPathRelativeToTopEquals(t, "hiddenapi cp rule input", expectedCpInput, actualCpInput) 272 273 android.AssertPathRelativeToTopEquals(t, "hiddenapi cp rule output", expectedCpOutput, actualCpOutput) 274 275 android.AssertStringEquals(t, "hiddenapi encode dex rule flags csv", expectedFlagsCsv, actualFlagsCsv) 276} 277 278func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) { 279 280 result := android.GroupFixturePreparers( 281 hiddenApiFixtureFactory, 282 FixtureConfigureBootJars("platform:foo"), 283 PrepareForTestWithJavaSdkLibraryFiles, 284 FixtureWithLastReleaseApis("foo"), 285 286 // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding 287 // is disabled. 288 android.FixtureAddTextFile("frameworks/base/Android.bp", ""), 289 ).RunTestWithBp(t, ` 290 java_sdk_library { 291 name: "foo", 292 srcs: ["a.java"], 293 shared_library: false, 294 compile_dex: true, 295 public: {enabled: true}, 296 } 297 `) 298 299 checkDexEncoded := func(t *testing.T, name, unencodedDexJar, encodedDexJar string) { 300 moduleForTests := result.ModuleForTests(name, "android_common") 301 302 encodeDexRule := moduleForTests.Rule("hiddenAPIEncodeDex") 303 actualUnencodedDexJar := encodeDexRule.Input 304 305 // Make sure that the module has its dex jar encoded. 306 android.AssertStringEquals(t, "encode embedded java_library", unencodedDexJar, actualUnencodedDexJar.String()) 307 308 // Make sure that the encoded dex jar is the exported one. 309 exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath() 310 android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar) 311 } 312 313 // The java_library embedded with the java_sdk_library must be dex encoded. 314 t.Run("foo", func(t *testing.T) { 315 expectedUnencodedDexJar := "out/soong/.intermediates/foo/android_common/aligned/foo.jar" 316 expectedEncodedDexJar := "out/soong/.intermediates/foo/android_common/hiddenapi/foo.jar" 317 checkDexEncoded(t, "foo", expectedUnencodedDexJar, expectedEncodedDexJar) 318 }) 319 320 // The dex jar of the child implementation java_library of the java_sdk_library is not currently 321 // dex encoded. 322 t.Run("foo.impl", func(t *testing.T) { 323 fooImpl := result.ModuleForTests("foo.impl", "android_common") 324 encodeDexRule := fooImpl.MaybeRule("hiddenAPIEncodeDex") 325 if encodeDexRule.Rule != nil { 326 t.Errorf("foo.impl is not expected to be encoded") 327 } 328 }) 329} 330