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 }), 207 android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"), 208 ).RunTestWithBp(t, ` 209 java_library { 210 name: "foo", 211 srcs: ["a.java"], 212 compile_dex: true, 213 } 214 `) 215 216 hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") 217 hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") 218 wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild) 219 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantPublicStubs) 220 221 wantSystemStubs := "--system-stub-classpath=" + generateSdkDexPath(tc.systemStub, tc.unbundledBuild) 222 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantSystemStubs) 223 224 wantTestStubs := "--test-stub-classpath=" + generateSdkDexPath(tc.testStub, tc.unbundledBuild) 225 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantTestStubs) 226 227 wantCorePlatformStubs := "--core-platform-stub-classpath=" + generateDexPath(defaultJavaDir, tc.corePlatformStub) 228 android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantCorePlatformStubs) 229 }) 230 } 231} 232 233func generateDexedPath(subDir, dex, module string) string { 234 return fmt.Sprintf("out/soong/.intermediates/%s/android_common/%s/%s.jar", subDir, dex, module) 235} 236 237func generateDexPath(moduleDir string, module string) string { 238 return generateDexedPath(filepath.Join(moduleDir, module), "dex", module) 239} 240 241func generateSdkDexPath(module string, unbundled bool) string { 242 if unbundled { 243 return generateDexedPath("prebuilts/sdk/"+module, "dex", module) 244 } 245 return generateDexPath(defaultJavaDir, module) 246} 247 248func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { 249 250 // The idea behind this test is to ensure that when the build is 251 // confugured with a PrebuiltHiddenApiDir that the rules for the 252 // hiddenapi singleton copy the prebuilts to the typical output 253 // location, and then use that output location for the hiddenapi encode 254 // dex step. 255 256 // Where to find the prebuilt hiddenapi files: 257 prebuiltHiddenApiDir := "path/to/prebuilt/hiddenapi" 258 259 result := android.GroupFixturePreparers( 260 hiddenApiFixtureFactory, 261 FixtureConfigureBootJars("platform:foo"), 262 fixtureSetPrebuiltHiddenApiDirProductVariable(&prebuiltHiddenApiDir), 263 ).RunTestWithBp(t, ` 264 java_import { 265 name: "foo", 266 jars: ["a.jar"], 267 compile_dex: true, 268 } 269 `) 270 271 expectedCpInput := prebuiltHiddenApiDir + "/hiddenapi-flags.csv" 272 expectedCpOutput := "out/soong/hiddenapi/hiddenapi-flags.csv" 273 expectedFlagsCsv := "out/soong/hiddenapi/hiddenapi-flags.csv" 274 275 foo := result.ModuleForTests("foo", "android_common") 276 277 hiddenAPI := result.SingletonForTests("hiddenapi") 278 cpRule := hiddenAPI.Rule("Cp") 279 actualCpInput := cpRule.BuildParams.Input 280 actualCpOutput := cpRule.BuildParams.Output 281 encodeDexRule := foo.Rule("hiddenAPIEncodeDex") 282 actualFlagsCsv := encodeDexRule.BuildParams.Args["flagsCsv"] 283 284 android.AssertPathRelativeToTopEquals(t, "hiddenapi cp rule input", expectedCpInput, actualCpInput) 285 286 android.AssertPathRelativeToTopEquals(t, "hiddenapi cp rule output", expectedCpOutput, actualCpOutput) 287 288 android.AssertStringEquals(t, "hiddenapi encode dex rule flags csv", expectedFlagsCsv, actualFlagsCsv) 289} 290 291func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) { 292 293 result := android.GroupFixturePreparers( 294 hiddenApiFixtureFactory, 295 FixtureConfigureBootJars("platform:foo"), 296 PrepareForTestWithJavaSdkLibraryFiles, 297 FixtureWithLastReleaseApis("foo"), 298 299 // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding 300 // is disabled. 301 android.FixtureAddTextFile("frameworks/base/Android.bp", ""), 302 ).RunTestWithBp(t, ` 303 java_sdk_library { 304 name: "foo", 305 srcs: ["a.java"], 306 shared_library: false, 307 compile_dex: true, 308 public: {enabled: true}, 309 } 310 `) 311 312 checkDexEncoded := func(t *testing.T, name, unencodedDexJar, encodedDexJar string) { 313 moduleForTests := result.ModuleForTests(name+".impl", "android_common") 314 315 encodeDexRule := moduleForTests.Rule("hiddenAPIEncodeDex") 316 actualUnencodedDexJar := encodeDexRule.Input 317 318 // Make sure that the module has its dex jar encoded. 319 android.AssertStringEquals(t, "encode embedded java_library", unencodedDexJar, actualUnencodedDexJar.String()) 320 321 // Make sure that the encoded dex jar is the exported one. 322 errCtx := moduleErrorfTestCtx{} 323 exportedDexJar := moduleForTests.Module().(UsesLibraryDependency).DexJarBuildPath(errCtx).Path() 324 android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar) 325 } 326 327 // The java_library embedded with the java_sdk_library must be dex encoded. 328 t.Run("foo", func(t *testing.T) { 329 expectedUnencodedDexJar := "out/soong/.intermediates/foo.impl/android_common/aligned/foo.jar" 330 expectedEncodedDexJar := "out/soong/.intermediates/foo.impl/android_common/hiddenapi/foo.jar" 331 checkDexEncoded(t, "foo", expectedUnencodedDexJar, expectedEncodedDexJar) 332 }) 333} 334