• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2021 The Android Open Source Project
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	"strings"
19	"testing"
20
21	"android/soong/android"
22	"android/soong/dexpreopt"
23)
24
25// Contains some simple tests for bootclasspath_fragment logic, additional tests can be found in
26// apex/bootclasspath_fragment_test.go as the ART boot image requires modules from the ART apex.
27
28var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers(
29	PrepareForTestWithJavaDefaultModules,
30	dexpreopt.PrepareForTestByEnablingDexpreopt,
31)
32
33func TestBootclasspathFragment_UnknownImageName(t *testing.T) {
34	t.Parallel()
35	prepareForTestWithBootclasspathFragment.
36		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
37			`\Qimage_name: unknown image name "unknown", expected "art"\E`)).
38		RunTestWithBp(t, `
39			bootclasspath_fragment {
40				name: "unknown-bootclasspath-fragment",
41				image_name: "unknown",
42				contents: ["foo"],
43			}
44
45			java_library {
46				name: "foo",
47				srcs: ["foo.java"],
48				installable: true,
49			}
50		`)
51}
52
53func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) {
54	t.Parallel()
55	prepareForTestWithBootclasspathFragment.
56		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
57			`\Qimage_name: unknown image name "unknown", expected "art"\E`)).
58		RunTestWithBp(t, `
59			prebuilt_bootclasspath_fragment {
60				name: "unknown-bootclasspath-fragment",
61				image_name: "unknown",
62				contents: ["foo"],
63			}
64
65			java_import {
66				name: "foo",
67				jars: ["foo.jar"],
68			}
69		`)
70}
71
72func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T) {
73	t.Parallel()
74	android.GroupFixturePreparers(
75		prepareForTestWithBootclasspathFragment,
76		dexpreopt.FixtureSetArtBootJars("platform:foo", "apex:bar"),
77	).
78		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
79			`\QArtApexJars is invalid as it requests a platform variant of "foo"\E`)).
80		RunTestWithBp(t, `
81			bootclasspath_fragment {
82				name: "bootclasspath-fragment",
83				image_name: "art",
84				contents: ["foo", "bar"],
85				apex_available: [
86					"apex",
87				],
88			}
89
90			java_library {
91				name: "foo",
92				srcs: ["foo.java"],
93				installable: true,
94			}
95
96			java_library {
97				name: "bar",
98				srcs: ["bar.java"],
99				installable: true,
100			}
101		`)
102}
103
104func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testing.T) {
105	t.Parallel()
106	android.GroupFixturePreparers(
107		prepareForTestWithBootclasspathFragment,
108		dexpreopt.FixtureSetArtBootJars("apex1:foo", "apex2:bar"),
109	).
110		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
111			`\QArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex "apex1" and "apex2"\E`)).
112		RunTestWithBp(t, `
113			bootclasspath_fragment {
114				name: "bootclasspath-fragment",
115				image_name: "art",
116				contents: ["foo", "bar"],
117				apex_available: [
118					"apex1",
119					"apex2",
120				],
121			}
122
123			java_library {
124				name: "foo",
125				srcs: ["foo.java"],
126				installable: true,
127			}
128
129			java_library {
130				name: "bar",
131				srcs: ["bar.java"],
132				installable: true,
133			}
134		`)
135}
136
137func TestBootclasspathFragment_Coverage(t *testing.T) {
138	t.Parallel()
139	prepareWithBp := android.FixtureWithRootAndroidBp(`
140		bootclasspath_fragment {
141			name: "myfragment",
142			contents: [
143				"mybootlib",
144			],
145			api: {
146				stub_libs: [
147					"mysdklibrary",
148				],
149			},
150			coverage: {
151				contents: [
152					"coveragelib",
153				],
154				api: {
155					stub_libs: [
156						"mycoveragestubs",
157					],
158				},
159			},
160			hidden_api: {
161				split_packages: ["*"],
162			},
163		}
164
165		java_library {
166			name: "mybootlib",
167			srcs: ["Test.java"],
168			system_modules: "none",
169			sdk_version: "none",
170			compile_dex: true,
171		}
172
173		java_library {
174			name: "coveragelib",
175			srcs: ["Test.java"],
176			system_modules: "none",
177			sdk_version: "none",
178			compile_dex: true,
179		}
180
181		java_sdk_library {
182			name: "mysdklibrary",
183			srcs: ["Test.java"],
184			compile_dex: true,
185			public: {enabled: true},
186			system: {enabled: true},
187		}
188
189		java_sdk_library {
190			name: "mycoveragestubs",
191			srcs: ["Test.java"],
192			compile_dex: true,
193			public: {enabled: true},
194		}
195	`)
196
197	checkContents := func(t *testing.T, result *android.TestResult, expected ...string) {
198		module := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule)
199		eval := module.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext))
200		android.AssertArrayString(t, "contents property", expected, module.properties.Contents.GetOrDefault(eval, nil))
201	}
202
203	preparer := android.GroupFixturePreparers(
204		prepareForTestWithBootclasspathFragment,
205		PrepareForTestWithJavaSdkLibraryFiles,
206		FixtureWithLastReleaseApis("mysdklibrary", "mycoveragestubs"),
207		FixtureConfigureApexBootJars("someapex:mybootlib"),
208		prepareWithBp,
209	)
210
211	t.Run("without coverage", func(t *testing.T) {
212		t.Parallel()
213		result := preparer.RunTest(t)
214		checkContents(t, result, "mybootlib")
215	})
216
217	t.Run("with coverage", func(t *testing.T) {
218		t.Parallel()
219		result := android.GroupFixturePreparers(
220			prepareForTestWithFrameworkJacocoInstrumentation,
221			preparer,
222		).RunTest(t)
223		checkContents(t, result, "mybootlib", "coveragelib")
224	})
225}
226
227func TestBootclasspathFragment_StubLibs(t *testing.T) {
228	result := android.GroupFixturePreparers(
229		prepareForTestWithBootclasspathFragment,
230		PrepareForTestWithJavaSdkLibraryFiles,
231		FixtureWithLastReleaseApis("mysdklibrary", "myothersdklibrary", "mycoreplatform"),
232		FixtureConfigureApexBootJars("someapex:mysdklibrary"),
233		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
234	).RunTestWithBp(t, `
235		bootclasspath_fragment {
236			name: "myfragment",
237			contents: ["mysdklibrary"],
238			api: {
239				stub_libs: [
240					"mystublib",
241					"myothersdklibrary",
242				],
243			},
244			core_platform_api: {
245				stub_libs: ["mycoreplatform.stubs"],
246			},
247			hidden_api: {
248				split_packages: ["*"],
249			},
250		}
251
252		java_library {
253			name: "mystublib",
254			srcs: ["Test.java"],
255			system_modules: "none",
256			sdk_version: "none",
257			compile_dex: true,
258		}
259
260		java_sdk_library {
261			name: "mysdklibrary",
262			srcs: ["a.java"],
263			shared_library: false,
264			public: {enabled: true},
265			system: {enabled: true},
266		}
267
268		java_sdk_library {
269			name: "myothersdklibrary",
270			srcs: ["a.java"],
271			shared_library: false,
272			public: {enabled: true},
273		}
274
275		java_sdk_library {
276			name: "mycoreplatform",
277			srcs: ["a.java"],
278			shared_library: false,
279			public: {enabled: true},
280		}
281	`)
282
283	fragment := result.Module("myfragment", "android_common")
284	info, _ := android.OtherModuleProvider(result, fragment, HiddenAPIInfoProvider)
285
286	stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar"
287
288	// Stubs jars for mysdklibrary
289	publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable/android_common/dex/mysdklibrary.stubs.exportable.jar"
290	systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.exportable.system/android_common/dex/mysdklibrary.stubs.exportable.system.jar"
291
292	// Stubs jars for myothersdklibrary
293	otherPublicStubsJar := "out/soong/.intermediates/myothersdklibrary.stubs.exportable/android_common/dex/myothersdklibrary.stubs.exportable.jar"
294
295	// Check that SdkPublic uses public stubs for all sdk libraries.
296	android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{otherPublicStubsJar, publicStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(PublicHiddenAPIScope))
297
298	// Check that SdkSystem uses system stubs for mysdklibrary and public stubs for myothersdklibrary
299	// as it does not provide system stubs.
300	android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(SystemHiddenAPIScope))
301
302	// Check that SdkTest also uses system stubs for mysdklibrary as it does not provide test stubs
303	// and public stubs for myothersdklibrary as it does not provide test stubs either.
304	android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{otherPublicStubsJar, systemStubsJar, stubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(TestHiddenAPIScope))
305
306	// Check that SdkCorePlatform uses public stubs from the mycoreplatform library.
307	corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar"
308	android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.TransitiveStubDexJarsByScope.StubDexJarsForScope(CorePlatformHiddenAPIScope))
309
310	// Check the widest stubs.. The list contains the widest stub dex jar provided by each module.
311	expectedWidestPaths := []string{
312		// mycoreplatform's widest API is core platform.
313		corePlatformStubsJar,
314
315		// myothersdklibrary's widest API is public.
316		otherPublicStubsJar,
317
318		// sdklibrary's widest API is system.
319		systemStubsJar,
320
321		// mystublib's only provides one API and so it must be the widest.
322		stubsJar,
323	}
324
325	android.AssertPathsRelativeToTopEquals(t, "widest dex stubs jar", expectedWidestPaths, info.TransitiveStubDexJarsByScope.StubDexJarsForWidestAPIScope())
326}
327
328func TestFromTextWidestApiScope(t *testing.T) {
329	result := android.GroupFixturePreparers(
330		prepareForTestWithBootclasspathFragment,
331		PrepareForTestWithJavaSdkLibraryFiles,
332		android.FixtureModifyConfig(func(config android.Config) {
333			config.SetBuildFromTextStub(true)
334		}),
335		FixtureWithLastReleaseApis("mysdklibrary", "android-non-updatable"),
336		FixtureConfigureApexBootJars("someapex:mysdklibrary"),
337	).RunTestWithBp(t, `
338		bootclasspath_fragment {
339			name: "myfragment",
340			contents: ["mysdklibrary"],
341			additional_stubs: [
342				"android-non-updatable",
343			],
344			hidden_api: {
345				split_packages: ["*"],
346			},
347		}
348		java_sdk_library {
349			name: "mysdklibrary",
350			srcs: ["a.java"],
351			shared_library: false,
352			public: {enabled: true},
353			system: {enabled: true},
354		}
355		java_sdk_library {
356			name: "android-non-updatable",
357			srcs: ["b.java"],
358			compile_dex: true,
359			public: {
360				enabled: true,
361			},
362			system: {
363				enabled: true,
364			},
365			test: {
366				enabled: true,
367			},
368			module_lib: {
369				enabled: true,
370			},
371		}
372	`)
373
374	fragment := result.ModuleForTests(t, "myfragment", "android_common")
375	dependencyStubDexFlag := "--dependency-stub-dex=out/soong/.intermediates/default/java/android-non-updatable.stubs.test_module_lib/android_common/dex/android-non-updatable.stubs.test_module_lib.jar"
376	stubFlagsCommand := fragment.Output("modular-hiddenapi/stub-flags.csv").RuleParams.Command
377	android.AssertStringDoesContain(t,
378		"Stub flags generating command does not include the expected dependency stub dex file",
379		stubFlagsCommand, dependencyStubDexFlag)
380}
381
382func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) {
383	result := android.GroupFixturePreparers(
384		prepareForTestWithBootclasspathFragment,
385		PrepareForTestWithJavaSdkLibraryFiles,
386		FixtureWithLastReleaseApis("mysdklibrary", "mynewlibrary"),
387		FixtureConfigureApexBootJars("myapex:mybootlib", "myapex:mynewlibrary"),
388		android.MockFS{
389			"my-blocked.txt":                   nil,
390			"my-max-target-o-low-priority.txt": nil,
391			"my-max-target-p.txt":              nil,
392			"my-max-target-q.txt":              nil,
393			"my-max-target-r-low-priority.txt": nil,
394			"my-removed.txt":                   nil,
395			"my-unsupported-packages.txt":      nil,
396			"my-unsupported.txt":               nil,
397			"my-new-max-target-q.txt":          nil,
398		}.AddToFixture(),
399		android.FixtureWithRootAndroidBp(`
400			bootclasspath_fragment {
401				name: "mybootclasspathfragment",
402				apex_available: ["myapex"],
403				contents: ["mybootlib", "mynewlibrary"],
404				hidden_api: {
405					unsupported: [
406							"my-unsupported.txt",
407					],
408					removed: [
409							"my-removed.txt",
410					],
411					max_target_r_low_priority: [
412							"my-max-target-r-low-priority.txt",
413					],
414					max_target_q: [
415							"my-max-target-q.txt",
416					],
417					max_target_p: [
418							"my-max-target-p.txt",
419					],
420					max_target_o_low_priority: [
421							"my-max-target-o-low-priority.txt",
422					],
423					blocked: [
424							"my-blocked.txt",
425					],
426					unsupported_packages: [
427							"my-unsupported-packages.txt",
428					],
429					split_packages: ["sdklibrary"],
430					package_prefixes: ["sdklibrary.all.mine"],
431					single_packages: ["sdklibrary.mine"],
432				},
433			}
434
435			java_library {
436				name: "mybootlib",
437				apex_available: ["myapex"],
438				srcs: ["Test.java"],
439				system_modules: "none",
440				sdk_version: "none",
441				min_sdk_version: "1",
442				compile_dex: true,
443				permitted_packages: ["mybootlib"],
444			}
445
446			java_sdk_library {
447				name: "mynewlibrary",
448				apex_available: ["myapex"],
449				srcs: ["Test.java"],
450				min_sdk_version: "10",
451				compile_dex: true,
452				public: {enabled: true},
453				permitted_packages: ["mysdklibrary"],
454				hidden_api: {
455					max_target_q: [
456							"my-new-max-target-q.txt",
457					],
458					split_packages: ["sdklibrary", "newlibrary"],
459					package_prefixes: ["newlibrary.all.mine"],
460					single_packages: ["newlibrary.mine"],
461				},
462			}
463		`),
464	).RunTest(t)
465
466	// Make sure that the library exports hidden API properties for use by the bootclasspath_fragment.
467	library := result.Module("mynewlibrary", "android_common")
468	info, _ := android.OtherModuleProvider(result, library, hiddenAPIPropertyInfoProvider)
469	android.AssertArrayString(t, "split packages", []string{"sdklibrary", "newlibrary"}, info.SplitPackages)
470	android.AssertArrayString(t, "package prefixes", []string{"newlibrary.all.mine"}, info.PackagePrefixes)
471	android.AssertArrayString(t, "single packages", []string{"newlibrary.mine"}, info.SinglePackages)
472	for _, c := range HiddenAPIFlagFileCategories {
473		expectedMaxTargetQPaths := []string(nil)
474		if c.PropertyName() == "max_target_q" {
475			expectedMaxTargetQPaths = []string{"my-new-max-target-q.txt"}
476		}
477		android.AssertPathsRelativeToTopEquals(t, c.PropertyName(), expectedMaxTargetQPaths, info.FlagFilesByCategory[c])
478	}
479
480	// Make sure that the signature-patterns.csv is passed all the appropriate package properties
481	// from the bootclasspath_fragment and its contents.
482	fragment := result.ModuleForTests(t, "mybootclasspathfragment", "android_common")
483	rule := fragment.Output("modular-hiddenapi/signature-patterns.csv")
484	expectedCommand := strings.Join([]string{
485		"--split-package newlibrary",
486		"--split-package sdklibrary",
487		"--package-prefix newlibrary.all.mine",
488		"--package-prefix sdklibrary.all.mine",
489		"--single-package newlibrary.mine",
490		"--single-package sdklibrary",
491	}, " ")
492	android.AssertStringDoesContain(t, "signature patterns command", rule.RuleParams.Command, expectedCommand)
493}
494
495func TestBootclasspathFragment_Test(t *testing.T) {
496	result := android.GroupFixturePreparers(
497		prepareForTestWithBootclasspathFragment,
498		PrepareForTestWithJavaSdkLibraryFiles,
499		FixtureWithLastReleaseApis("mysdklibrary"),
500	).RunTestWithBp(t, `
501		bootclasspath_fragment {
502			name: "myfragment",
503			contents: ["mysdklibrary"],
504			hidden_api: {
505				split_packages: [],
506			},
507		}
508
509		bootclasspath_fragment_test {
510			name: "a_test_fragment",
511			contents: ["mysdklibrary"],
512			hidden_api: {
513				split_packages: [],
514			},
515		}
516
517
518		java_sdk_library {
519			name: "mysdklibrary",
520			srcs: ["a.java"],
521			shared_library: false,
522			public: {enabled: true},
523			system: {enabled: true},
524		}
525	`)
526
527	fragment := result.Module("myfragment", "android_common").(*BootclasspathFragmentModule)
528	android.AssertBoolEquals(t, "not a test fragment", false, fragment.isTestFragment())
529
530	fragment = result.Module("a_test_fragment", "android_common").(*BootclasspathFragmentModule)
531	android.AssertBoolEquals(t, "is a test fragment by type", true, fragment.isTestFragment())
532}
533