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