xref: /aosp_15_r20/build/soong/apex/platform_bootclasspath_test.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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 apex
16
17import (
18	"fmt"
19	"strings"
20	"testing"
21
22	"android/soong/android"
23	"android/soong/dexpreopt"
24	"android/soong/java"
25
26	"github.com/google/blueprint"
27	"github.com/google/blueprint/proptools"
28)
29
30// Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
31// apexes.
32
33var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers(
34	java.PrepareForTestWithJavaDefaultModules,
35	PrepareForTestWithApexBuildComponents,
36)
37
38func TestPlatformBootclasspath_Fragments(t *testing.T) {
39	t.Parallel()
40	result := android.GroupFixturePreparers(
41		prepareForTestWithPlatformBootclasspath,
42		prepareForTestWithMyapex,
43		java.PrepareForTestWithJavaSdkLibraryFiles,
44		java.FixtureWithLastReleaseApis("foo"),
45		java.FixtureConfigureApexBootJars("myapex:bar"),
46		android.FixtureWithRootAndroidBp(`
47			platform_bootclasspath {
48				name: "platform-bootclasspath",
49				fragments: [
50					{
51						apex: "myapex",
52						module:"bar-fragment",
53					},
54				],
55				hidden_api: {
56					unsupported: [
57							"unsupported.txt",
58					],
59					removed: [
60							"removed.txt",
61					],
62					max_target_r_low_priority: [
63							"max-target-r-low-priority.txt",
64					],
65					max_target_q: [
66							"max-target-q.txt",
67					],
68					max_target_p: [
69							"max-target-p.txt",
70					],
71					max_target_o_low_priority: [
72							"max-target-o-low-priority.txt",
73					],
74					blocked: [
75							"blocked.txt",
76					],
77					unsupported_packages: [
78							"unsupported-packages.txt",
79					],
80				},
81			}
82
83			apex {
84				name: "myapex",
85				key: "myapex.key",
86				bootclasspath_fragments: [
87					"bar-fragment",
88				],
89				updatable: false,
90				min_sdk_version: "30", // R
91			}
92
93			apex_key {
94				name: "myapex.key",
95				public_key: "testkey.avbpubkey",
96				private_key: "testkey.pem",
97			}
98
99			bootclasspath_fragment {
100				name: "bar-fragment",
101				contents: ["bar"],
102				apex_available: ["myapex"],
103				api: {
104					stub_libs: ["foo"],
105				},
106				hidden_api: {
107					unsupported: [
108							"bar-unsupported.txt",
109					],
110					removed: [
111							"bar-removed.txt",
112					],
113					max_target_r_low_priority: [
114							"bar-max-target-r-low-priority.txt",
115					],
116					max_target_q: [
117							"bar-max-target-q.txt",
118					],
119					max_target_p: [
120							"bar-max-target-p.txt",
121					],
122					max_target_o_low_priority: [
123							"bar-max-target-o-low-priority.txt",
124					],
125					blocked: [
126							"bar-blocked.txt",
127					],
128					unsupported_packages: [
129							"bar-unsupported-packages.txt",
130					],
131					split_packages: ["*"],
132				},
133			}
134
135			java_library {
136				name: "bar",
137				apex_available: ["myapex"],
138				srcs: ["a.java"],
139				system_modules: "none",
140				sdk_version: "none",
141				compile_dex: true,
142				permitted_packages: ["bar"],
143				min_sdk_version: "30", // R
144			}
145
146			java_sdk_library {
147				name: "foo",
148				srcs: ["a.java"],
149				public: {
150					enabled: true,
151				},
152				compile_dex: true,
153			}
154		`),
155	).RunTest(t)
156
157	pbcp := result.Module("platform-bootclasspath", "android_common")
158	info, _ := android.OtherModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
159
160	for _, category := range java.HiddenAPIFlagFileCategories {
161		name := category.PropertyName()
162		message := fmt.Sprintf("category %s", name)
163		filename := strings.ReplaceAll(name, "_", "-")
164		expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)}
165		android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
166	}
167
168	android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
169	android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
170	android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/index.csv"}, info.IndexPaths)
171
172	android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/filtered-stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
173	android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
174}
175
176// TestPlatformBootclasspath_LegacyPrebuiltFragment verifies that the
177// prebuilt_bootclasspath_fragment falls back to using the complete stub-flags/all-flags if the
178// filtered files are not provided.
179//
180// TODO: Remove once all prebuilts use the filtered_... properties.
181func TestPlatformBootclasspath_LegacyPrebuiltFragment(t *testing.T) {
182	t.Parallel()
183	result := android.GroupFixturePreparers(
184		prepareForTestWithPlatformBootclasspath,
185		java.FixtureConfigureApexBootJars("myapex:foo"),
186		java.PrepareForTestWithJavaSdkLibraryFiles,
187	).RunTestWithBp(t, `
188		prebuilt_apex {
189			name: "myapex",
190			src: "myapex.apex",
191			exported_bootclasspath_fragments: ["mybootclasspath-fragment"],
192		}
193
194		// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
195		// because AlwaysUsePrebuiltSdks() is true.
196		java_sdk_library_import {
197			name: "foo",
198			prefer: false,
199			shared_library: false,
200			permitted_packages: ["foo"],
201			public: {
202				jars: ["sdk_library/public/foo-stubs.jar"],
203				stub_srcs: ["sdk_library/public/foo_stub_sources"],
204				current_api: "sdk_library/public/foo.txt",
205				removed_api: "sdk_library/public/foo-removed.txt",
206				sdk_version: "current",
207			},
208			apex_available: ["myapex"],
209		}
210
211		prebuilt_bootclasspath_fragment {
212			name: "mybootclasspath-fragment",
213			apex_available: [
214				"myapex",
215			],
216			contents: [
217				"foo",
218			],
219			hidden_api: {
220				stub_flags: "prebuilt-stub-flags.csv",
221				annotation_flags: "prebuilt-annotation-flags.csv",
222				metadata: "prebuilt-metadata.csv",
223				index: "prebuilt-index.csv",
224				all_flags: "prebuilt-all-flags.csv",
225			},
226		}
227
228		platform_bootclasspath {
229			name: "myplatform-bootclasspath",
230			fragments: [
231				{
232					apex: "myapex",
233					module:"mybootclasspath-fragment",
234				},
235			],
236		}
237`,
238	)
239
240	pbcp := result.Module("myplatform-bootclasspath", "android_common")
241	info, _ := android.OtherModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
242
243	android.AssertArrayString(t, "stub flags", []string{"prebuilt-stub-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop())
244	android.AssertArrayString(t, "all flags", []string{"prebuilt-all-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop())
245}
246
247func TestPlatformBootclasspathDependencies(t *testing.T) {
248	t.Parallel()
249	result := android.GroupFixturePreparers(
250		prepareForTestWithPlatformBootclasspath,
251		prepareForTestWithArtApex,
252		prepareForTestWithMyapex,
253		// Configure some libraries in the art and framework boot images.
254		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo"),
255		java.FixtureConfigureApexBootJars("myapex:bar"),
256		java.PrepareForTestWithJavaSdkLibraryFiles,
257		java.FixtureWithLastReleaseApis("foo"),
258		java.PrepareForTestWithDexpreopt,
259		dexpreopt.FixtureDisableDexpreoptBootImages(false),
260		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
261	).RunTestWithBp(t, `
262		apex {
263			name: "com.android.art",
264			key: "com.android.art.key",
265 			bootclasspath_fragments: [
266				"art-bootclasspath-fragment",
267			],
268			updatable: false,
269		}
270
271		apex_key {
272			name: "com.android.art.key",
273			public_key: "com.android.art.avbpubkey",
274			private_key: "com.android.art.pem",
275		}
276
277		bootclasspath_fragment {
278			name: "art-bootclasspath-fragment",
279			image_name: "art",
280			apex_available: [
281				"com.android.art",
282			],
283			contents: [
284				"baz",
285				"quuz",
286			],
287			hidden_api: {
288				split_packages: ["*"],
289			},
290		}
291
292		java_library {
293			name: "baz",
294			apex_available: [
295				"com.android.art",
296			],
297			srcs: ["b.java"],
298			installable: true,
299			sdk_version: "core_current",
300		}
301
302		// Add a java_import that is not preferred and so won't have an appropriate apex variant created
303		// for it to make sure that the platform_bootclasspath doesn't try and add a dependency onto it.
304		java_import {
305			name: "baz",
306			apex_available: [
307				"com.android.art",
308			],
309			jars: ["b.jar"],
310		}
311
312		java_library {
313			name: "quuz",
314			apex_available: [
315				"com.android.art",
316			],
317			srcs: ["b.java"],
318			installable: true,
319		}
320
321		apex {
322			name: "myapex",
323			key: "myapex.key",
324			bootclasspath_fragments: [
325				"my-bootclasspath-fragment",
326			],
327			updatable: false,
328		}
329
330		bootclasspath_fragment {
331			name: "my-bootclasspath-fragment",
332			contents: ["bar"],
333			apex_available: ["myapex"],
334			hidden_api: {
335				split_packages: ["*"],
336			},
337		}
338
339		apex_key {
340			name: "myapex.key",
341			public_key: "testkey.avbpubkey",
342			private_key: "testkey.pem",
343		}
344
345		java_sdk_library {
346			name: "foo",
347			srcs: ["b.java"],
348		}
349
350		java_library {
351			name: "bar",
352			srcs: ["b.java"],
353			installable: true,
354			apex_available: ["myapex"],
355			permitted_packages: ["bar"],
356		}
357
358		platform_bootclasspath {
359			name: "myplatform-bootclasspath",
360
361			fragments: [
362				{
363					apex: "com.android.art",
364					module: "art-bootclasspath-fragment",
365				},
366				{
367					apex: "myapex",
368					module: "my-bootclasspath-fragment",
369				},
370			],
371		}
372`,
373	)
374
375	java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
376		// The configured contents of BootJars.
377		"com.android.art:baz",
378		"com.android.art:quuz",
379		"platform:foo",
380
381		// The configured contents of ApexBootJars.
382		"myapex:bar",
383	})
384
385	java.CheckPlatformBootclasspathFragments(t, result, "myplatform-bootclasspath", []string{
386		"com.android.art:art-bootclasspath-fragment",
387		"myapex:my-bootclasspath-fragment",
388	})
389
390	// Make sure that the myplatform-bootclasspath has the correct dependencies.
391	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
392		// source vs prebuilt selection metadata module
393		`platform:all_apex_contributions`,
394
395		// The following are stubs.
396		`platform:android_stubs_current_exportable`,
397		`platform:android_system_stubs_current_exportable`,
398		`platform:android_test_stubs_current_exportable`,
399		`platform:legacy.core.platform.api.stubs.exportable`,
400
401		// Needed for generating the boot image.
402		`platform:dex2oatd`,
403
404		// The configured contents of BootJars.
405		`com.android.art:baz`,
406		`com.android.art:quuz`,
407		`platform:foo`,
408
409		// The configured contents of ApexBootJars.
410		`myapex:bar`,
411
412		// The fragments.
413		`com.android.art:art-bootclasspath-fragment`,
414		`myapex:my-bootclasspath-fragment`,
415
416		// Impl lib of sdk_library for transitive srcjar generation
417		`platform:foo.impl`,
418	})
419}
420
421// TestPlatformBootclasspath_AlwaysUsePrebuiltSdks verifies that the build does not fail when
422// AlwaysUsePrebuiltSdk() returns true.
423func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
424	t.Parallel()
425	result := android.GroupFixturePreparers(
426		prepareForTestWithPlatformBootclasspath,
427		prepareForTestWithMyapex,
428		// Configure two libraries, the first is a java_sdk_library whose prebuilt will be used because
429		// of AlwaysUsePrebuiltsSdk(). The second is a normal library that is unaffected. The order
430		// matters, so that the dependencies resolved by the platform_bootclasspath matches the
431		// configured list.
432		java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
433		java.PrepareForTestWithJavaSdkLibraryFiles,
434		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
435			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
436		}),
437		android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"),
438
439		java.FixtureWithPrebuiltApis(map[string][]string{
440			"current": {},
441			"30":      {"foo"},
442		}),
443	).RunTestWithBp(t, `
444		apex {
445			name: "myapex",
446			key: "myapex.key",
447			bootclasspath_fragments: [
448				"mybootclasspath-fragment",
449			],
450			updatable: false,
451		}
452
453		apex_key {
454			name: "myapex.key",
455			public_key: "testkey.avbpubkey",
456			private_key: "testkey.pem",
457		}
458
459		java_library {
460			name: "bar",
461			srcs: ["b.java"],
462			installable: true,
463			apex_available: ["myapex"],
464			permitted_packages: ["bar"],
465		}
466
467		java_sdk_library {
468			name: "foo",
469			srcs: ["b.java"],
470			shared_library: false,
471			public: {
472				enabled: true,
473			},
474			apex_available: ["myapex"],
475			permitted_packages: ["foo"],
476		}
477
478		prebuilt_apex {
479			name: "myapex",
480			src: "myapex.apex",
481			exported_bootclasspath_fragments: ["mybootclasspath-fragment"],
482		}
483
484		// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
485		// because AlwaysUsePrebuiltSdks() is true.
486		java_sdk_library_import {
487			name: "foo",
488			prefer: false,
489			shared_library: false,
490			permitted_packages: ["foo"],
491			public: {
492				jars: ["sdk_library/public/foo-stubs.jar"],
493				stub_srcs: ["sdk_library/public/foo_stub_sources"],
494				current_api: "sdk_library/public/foo.txt",
495				removed_api: "sdk_library/public/foo-removed.txt",
496				sdk_version: "current",
497			},
498			apex_available: ["myapex"],
499		}
500
501		// This always depends on the source foo module, its dependencies are not affected by the
502		// AlwaysUsePrebuiltSdks().
503		bootclasspath_fragment {
504			name: "mybootclasspath-fragment",
505			apex_available: [
506				"myapex",
507			],
508			contents: [
509				"foo", "bar",
510			],
511			hidden_api: {
512				split_packages: ["*"],
513			},
514		}
515
516		prebuilt_bootclasspath_fragment {
517			name: "mybootclasspath-fragment",
518			apex_available: [
519				"myapex",
520			],
521			contents: [
522				"foo",
523			],
524			hidden_api: {
525				stub_flags: "",
526				annotation_flags: "",
527				metadata: "",
528				index: "",
529				all_flags: "",
530			},
531		}
532
533		platform_bootclasspath {
534			name: "myplatform-bootclasspath",
535			fragments: [
536				{
537					apex: "myapex",
538					module:"mybootclasspath-fragment",
539				},
540			],
541		}
542`,
543	)
544
545	java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
546		// The configured contents of BootJars.
547		"myapex:prebuilt_foo",
548		"myapex:bar",
549	})
550
551	// Make sure that the myplatform-bootclasspath has the correct dependencies.
552	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
553		// source vs prebuilt selection metadata module
554		`platform:all_apex_contributions`,
555
556		// The following are stubs.
557		"platform:prebuilt_sdk_public_current_android",
558		"platform:prebuilt_sdk_system_current_android",
559		"platform:prebuilt_sdk_test_current_android",
560
561		// Not a prebuilt as no prebuilt existed when it was added.
562		"platform:legacy.core.platform.api.stubs.exportable",
563
564		// The platform_bootclasspath intentionally adds dependencies on both source and prebuilt
565		// modules when available as it does not know which one will be preferred.
566		"myapex:foo",
567		"myapex:prebuilt_foo",
568
569		// Only a source module exists.
570		"myapex:bar",
571
572		// The fragments.
573		"myapex:mybootclasspath-fragment",
574		"myapex:prebuilt_mybootclasspath-fragment",
575
576		// Impl lib of sdk_library for transitive srcjar generation
577		"platform:foo.impl",
578	})
579}
580
581// CheckModuleDependencies checks the dependencies of the selected module against the expected list.
582//
583// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
584// name of the apex, or platform is it is not part of an apex and <module> is the module name.
585func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
586	t.Helper()
587	module := ctx.ModuleForTests(name, variant).Module()
588	modules := []android.Module{}
589	ctx.VisitDirectDeps(module, func(m blueprint.Module) {
590		modules = append(modules, m.(android.Module))
591	})
592
593	pairs := java.ApexNamePairsFromModules(ctx, modules)
594	android.AssertDeepEquals(t, "module dependencies", expected, pairs)
595}
596
597// TestPlatformBootclasspath_IncludesRemainingApexJars verifies that any apex boot jar is present in
598// platform_bootclasspath's classpaths.proto config, if the apex does not generate its own config
599// by setting generate_classpaths_proto property to false.
600func TestPlatformBootclasspath_IncludesRemainingApexJars(t *testing.T) {
601	t.Parallel()
602	result := android.GroupFixturePreparers(
603		prepareForTestWithPlatformBootclasspath,
604		prepareForTestWithMyapex,
605		java.FixtureConfigureApexBootJars("myapex:foo"),
606		android.FixtureWithRootAndroidBp(`
607			platform_bootclasspath {
608				name: "platform-bootclasspath",
609				fragments: [
610					{
611						apex: "myapex",
612						module:"foo-fragment",
613					},
614				],
615			}
616
617			apex {
618				name: "myapex",
619				key: "myapex.key",
620				bootclasspath_fragments: ["foo-fragment"],
621				updatable: false,
622			}
623
624			apex_key {
625				name: "myapex.key",
626				public_key: "testkey.avbpubkey",
627				private_key: "testkey.pem",
628			}
629
630			bootclasspath_fragment {
631				name: "foo-fragment",
632				generate_classpaths_proto: false,
633				contents: ["foo"],
634				apex_available: ["myapex"],
635				hidden_api: {
636					split_packages: ["*"],
637				},
638			}
639
640			java_library {
641				name: "foo",
642				srcs: ["a.java"],
643				system_modules: "none",
644				sdk_version: "none",
645				compile_dex: true,
646				apex_available: ["myapex"],
647				permitted_packages: ["foo"],
648			}
649		`),
650	).RunTest(t)
651
652	java.CheckClasspathFragmentProtoContentInfoProvider(t, result,
653		true,         // proto should be generated
654		"myapex:foo", // apex doesn't generate its own config, so must be in platform_bootclasspath
655		"bootclasspath.pb",
656		"out/soong/target/product/test_device/system/etc/classpaths",
657	)
658}
659
660func TestBootJarNotInApex(t *testing.T) {
661	t.Parallel()
662	android.GroupFixturePreparers(
663		prepareForTestWithPlatformBootclasspath,
664		PrepareForTestWithApexBuildComponents,
665		prepareForTestWithMyapex,
666		java.FixtureConfigureApexBootJars("myapex:foo"),
667	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
668		`dependency "foo" of "myplatform-bootclasspath" missing variant`)).
669		RunTestWithBp(t, `
670			apex {
671				name: "myapex",
672				key: "myapex.key",
673				updatable: false,
674			}
675
676			apex_key {
677				name: "myapex.key",
678				public_key: "testkey.avbpubkey",
679				private_key: "testkey.pem",
680			}
681
682			java_library {
683				name: "foo",
684				srcs: ["b.java"],
685				installable: true,
686				apex_available: [
687					"myapex",
688				],
689			}
690
691			bootclasspath_fragment {
692				name: "not-in-apex-fragment",
693				contents: [
694					"foo",
695				],
696				hidden_api: {
697					split_packages: ["*"],
698				},
699			}
700
701			platform_bootclasspath {
702				name: "myplatform-bootclasspath",
703			}
704		`)
705}
706
707func TestBootFragmentNotInApex(t *testing.T) {
708	t.Parallel()
709	android.GroupFixturePreparers(
710		prepareForTestWithPlatformBootclasspath,
711		PrepareForTestWithApexBuildComponents,
712		prepareForTestWithMyapex,
713		java.FixtureConfigureApexBootJars("myapex:foo"),
714	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
715		`library foo.*have no corresponding fragment.*`)).RunTestWithBp(t, `
716			apex {
717				name: "myapex",
718				key: "myapex.key",
719				java_libs: ["foo"],
720				updatable: false,
721			}
722
723			apex_key {
724				name: "myapex.key",
725				public_key: "testkey.avbpubkey",
726				private_key: "testkey.pem",
727			}
728
729			java_library {
730				name: "foo",
731				srcs: ["b.java"],
732				installable: true,
733				apex_available: ["myapex"],
734				permitted_packages: ["foo"],
735			}
736
737			bootclasspath_fragment {
738				name: "not-in-apex-fragment",
739				contents: ["foo"],
740				hidden_api: {
741					split_packages: ["*"],
742				},
743			}
744
745			platform_bootclasspath {
746				name: "myplatform-bootclasspath",
747			}
748		`)
749}
750
751func TestNonBootJarInFragment(t *testing.T) {
752	t.Parallel()
753	android.GroupFixturePreparers(
754		prepareForTestWithPlatformBootclasspath,
755		PrepareForTestWithApexBuildComponents,
756		prepareForTestWithMyapex,
757		java.FixtureConfigureApexBootJars("myapex:foo"),
758	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
759		`in contents must also be declared in PRODUCT_APEX_BOOT_JARS`)).
760		RunTestWithBp(t, `
761			apex {
762				name: "myapex",
763				key: "myapex.key",
764				bootclasspath_fragments: ["apex-fragment"],
765				updatable: false,
766			}
767
768			apex_key {
769				name: "myapex.key",
770				public_key: "testkey.avbpubkey",
771				private_key: "testkey.pem",
772			}
773
774			java_library {
775				name: "foo",
776				srcs: ["b.java"],
777				installable: true,
778				apex_available: ["myapex"],
779				permitted_packages: ["foo"],
780			}
781
782			java_library {
783				name: "bar",
784				srcs: ["b.java"],
785				installable: true,
786				apex_available: ["myapex"],
787				permitted_packages: ["bar"],
788			}
789
790			bootclasspath_fragment {
791				name: "apex-fragment",
792				contents: ["foo", "bar"],
793				apex_available:[ "myapex" ],
794				hidden_api: {
795					split_packages: ["*"],
796				},
797			}
798
799			platform_bootclasspath {
800				name: "myplatform-bootclasspath",
801				fragments: [{
802						apex: "myapex",
803						module:"apex-fragment",
804				}],
805			}
806		`)
807}
808
809// Skip bcp_fragment content validation of source apexes if prebuilts are active.
810func TestNonBootJarInPrebuilts(t *testing.T) {
811	t.Parallel()
812	testCases := []struct {
813		description               string
814		selectedApexContributions string
815		expectedError             string
816	}{
817		{
818			description:               "source is active",
819			selectedApexContributions: "",
820			expectedError:             "in contents must also be declared in PRODUCT_APEX_BOOT_JARS",
821		},
822		{
823			description:               "prebuilts are active",
824			selectedApexContributions: "myapex.prebuilt.contributions",
825			expectedError:             "", // skip content validation of source bcp fragment
826		},
827	}
828	bp := `
829// Source
830apex {
831	name: "myapex",
832	key: "myapex.key",
833	bootclasspath_fragments: ["apex-fragment"],
834	updatable: false,
835	min_sdk_version: "29",
836}
837
838override_apex {
839	name: "myapex.override", // overrides the min_sdk_version, thereby creating different variants of its transitive deps
840	base: "myapex",
841	min_sdk_version: "34",
842}
843
844apex_key {
845	name: "myapex.key",
846	public_key: "testkey.avbpubkey",
847	private_key: "testkey.pem",
848}
849
850java_library {
851	name: "foo",
852	srcs: ["b.java"],
853	installable: true,
854	apex_available: ["myapex"],
855	permitted_packages: ["foo"],
856	min_sdk_version: "29",
857}
858
859java_library {
860	name: "bar",
861	srcs: ["b.java"],
862	installable: true,
863	apex_available: ["myapex"],
864	permitted_packages: ["bar"],
865	min_sdk_version: "29",
866}
867
868bootclasspath_fragment {
869	name: "apex-fragment",
870	contents: ["foo", "bar"],
871	apex_available:[ "myapex" ],
872	hidden_api: {
873		split_packages: ["*"],
874	},
875}
876
877platform_bootclasspath {
878	name: "myplatform-bootclasspath",
879	fragments: [{
880			apex: "myapex",
881			module:"apex-fragment",
882	}],
883}
884
885// prebuilts
886prebuilt_apex {
887	name: "myapex",
888		apex_name: "myapex",
889		src: "myapex.apex",
890		exported_bootclasspath_fragments: ["apex-fragment"],
891	}
892
893	prebuilt_bootclasspath_fragment {
894		name: "apex-fragment",
895		contents: ["foo"],
896		hidden_api: {
897			annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
898			metadata: "my-bootclasspath-fragment/metadata.csv",
899			index: "my-bootclasspath-fragment/index.csv",
900			stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
901			all_flags: "my-bootclasspath-fragment/all-flags.csv",
902		},
903	}
904	java_import {
905		name: "foo",
906		jars: ["foo.jar"],
907	}
908
909apex_contributions {
910	name: "myapex.prebuilt.contributions",
911	api_domain: "myapex",
912	contents: ["prebuilt_myapex"],
913}
914`
915
916	for _, tc := range testCases {
917		fixture := android.GroupFixturePreparers(
918			prepareForTestWithPlatformBootclasspath,
919			PrepareForTestWithApexBuildComponents,
920			prepareForTestWithMyapex,
921			java.FixtureConfigureApexBootJars("myapex:foo"),
922			android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ADSERVICES", tc.selectedApexContributions),
923		)
924		if tc.expectedError != "" {
925			fixture = fixture.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(tc.expectedError))
926		}
927		fixture.RunTestWithBp(t, bp)
928	}
929
930}
931
932// Source and prebuilt apex provide different set of boot jars
933func TestNonBootJarMissingInPrebuiltFragment(t *testing.T) {
934	t.Parallel()
935	bp := `
936		apex {
937			name: "myapex",
938			key: "myapex.key",
939			bootclasspath_fragments: ["apex-fragment"],
940			updatable: false,
941		}
942
943		apex_key {
944			name: "myapex.key",
945			public_key: "testkey.avbpubkey",
946			private_key: "testkey.pem",
947		}
948
949		java_library {
950			name: "foo",
951			srcs: ["b.java"],
952			installable: true,
953			apex_available: ["myapex"],
954			permitted_packages: ["foo"],
955		}
956
957		java_library {
958			name: "bar",
959			srcs: ["b.java"],
960			installable: true,
961			apex_available: ["myapex"],
962			permitted_packages: ["bar"],
963		}
964
965		bootclasspath_fragment {
966			name: "apex-fragment",
967			contents: ["foo", "bar"],
968			apex_available:[ "myapex" ],
969			hidden_api: {
970				split_packages: ["*"],
971			},
972		}
973
974		prebuilt_apex {
975			name: "com.google.android.myapex", // mainline prebuilt selection logic in soong relies on the naming convention com.google.android
976			apex_name: "myapex",
977			source_apex_name: "myapex",
978			src: "myapex.apex",
979			exported_bootclasspath_fragments: ["apex-fragment"],
980		}
981
982		java_import {
983			name: "foo",
984			jars: ["foo.jar"],
985			apex_available: ["myapex"],
986			permitted_packages: ["foo"],
987		}
988
989		prebuilt_bootclasspath_fragment {
990			name: "apex-fragment",
991			contents: ["foo"], // Unlike the source fragment, this is missing bar
992			apex_available:[ "myapex" ],
993			hidden_api: {
994				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
995				metadata: "my-bootclasspath-fragment/metadata.csv",
996				index: "my-bootclasspath-fragment/index.csv",
997				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
998				all_flags: "my-bootclasspath-fragment/all-flags.csv",
999			},
1000		}
1001
1002		// Another prebuilt apex, but this is not selected during the build.
1003		prebuilt_apex {
1004			name: "com.google.android.myapex.v2", // mainline prebuilt selection logic in soong relies on the naming convention com.google.android
1005			apex_name: "myapex",
1006			source_apex_name: "myapex",
1007			src: "myapex.apex",
1008			exported_bootclasspath_fragments: ["apex-fragment.v2"],
1009		}
1010
1011		java_import {
1012			name: "bar",
1013			jars: ["bar.jar"],
1014			apex_available: ["myapex"],
1015			permitted_packages: ["bar"],
1016		}
1017
1018		prebuilt_bootclasspath_fragment {
1019			name: "apex-fragment.v2",
1020			contents: ["bar"], // Unlike the source fragment, this is missing foo
1021			apex_available:[ "myapex" ],
1022			hidden_api: {
1023				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
1024				metadata: "my-bootclasspath-fragment/metadata.csv",
1025				index: "my-bootclasspath-fragment/index.csv",
1026				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
1027				all_flags: "my-bootclasspath-fragment/all-flags.csv",
1028			},
1029		}
1030
1031
1032		apex_contributions {
1033			name: "my_apex_contributions",
1034			api_domain: "myapex",
1035			contents: [%v],
1036		}
1037	`
1038	testCases := []struct {
1039		desc                     string
1040		configuredBootJars       []string
1041		apexContributionContents string
1042		errorExpected            bool
1043	}{
1044		{
1045			desc:               "Source apex is selected, and APEX_BOOT_JARS is correctly configured for source apex builds",
1046			configuredBootJars: []string{"myapex:foo", "myapex:bar"},
1047		},
1048		{
1049			desc:               "Source apex is selected, and APEX_BOOT_JARS is missing bar",
1050			configuredBootJars: []string{"myapex:foo"},
1051			errorExpected:      true,
1052		},
1053		{
1054			desc:                     "Prebuilt apex is selected, and APEX_BOOT_JARS is correctly configured for prebuilt apex build",
1055			configuredBootJars:       []string{"myapex:foo"},
1056			apexContributionContents: `"prebuilt_com.google.android.myapex"`,
1057		},
1058		{
1059			desc:                     "Prebuilt apex is selected, and APEX_BOOT_JARS is missing foo",
1060			configuredBootJars:       []string{"myapex:bar"},
1061			apexContributionContents: `"prebuilt_com.google.android.myapex"`,
1062			errorExpected:            true,
1063		},
1064	}
1065
1066	for _, tc := range testCases {
1067		fixture := android.GroupFixturePreparers(
1068			prepareForTestWithPlatformBootclasspath,
1069			PrepareForTestWithApexBuildComponents,
1070			prepareForTestWithMyapex,
1071			java.FixtureConfigureApexBootJars(tc.configuredBootJars...),
1072			android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", "my_apex_contributions"),
1073		)
1074		if tc.errorExpected {
1075			fixture = fixture.ExtendWithErrorHandler(
1076				android.FixtureExpectsAtLeastOneErrorMatchingPattern(`in contents.*must also be declared in PRODUCT_APEX_BOOT_JARS`),
1077			)
1078		}
1079		fixture.RunTestWithBp(t, fmt.Sprintf(bp, tc.apexContributionContents))
1080	}
1081}
1082