xref: /aosp_15_r20/build/soong/java/hiddenapi_singleton_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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