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