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