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	result := android.GroupFixturePreparers(
40		prepareForTestWithPlatformBootclasspath,
41		prepareForTestWithMyapex,
42		java.PrepareForTestWithJavaSdkLibraryFiles,
43		java.FixtureWithLastReleaseApis("foo"),
44		java.FixtureConfigureApexBootJars("myapex:bar"),
45		android.FixtureWithRootAndroidBp(`
46			platform_bootclasspath {
47				name: "platform-bootclasspath",
48				fragments: [
49					{
50						apex: "myapex",
51						module:"bar-fragment",
52					},
53				],
54				hidden_api: {
55					unsupported: [
56							"unsupported.txt",
57					],
58					removed: [
59							"removed.txt",
60					],
61					max_target_r_low_priority: [
62							"max-target-r-low-priority.txt",
63					],
64					max_target_q: [
65							"max-target-q.txt",
66					],
67					max_target_p: [
68							"max-target-p.txt",
69					],
70					max_target_o_low_priority: [
71							"max-target-o-low-priority.txt",
72					],
73					blocked: [
74							"blocked.txt",
75					],
76					unsupported_packages: [
77							"unsupported-packages.txt",
78					],
79				},
80			}
81
82			apex {
83				name: "myapex",
84				key: "myapex.key",
85				bootclasspath_fragments: [
86					"bar-fragment",
87				],
88				updatable: false,
89				min_sdk_version: "30", // R
90			}
91
92			apex_key {
93				name: "myapex.key",
94				public_key: "testkey.avbpubkey",
95				private_key: "testkey.pem",
96			}
97
98			bootclasspath_fragment {
99				name: "bar-fragment",
100				contents: ["bar"],
101				apex_available: ["myapex"],
102				api: {
103					stub_libs: ["foo"],
104				},
105				hidden_api: {
106					unsupported: [
107							"bar-unsupported.txt",
108					],
109					removed: [
110							"bar-removed.txt",
111					],
112					max_target_r_low_priority: [
113							"bar-max-target-r-low-priority.txt",
114					],
115					max_target_q: [
116							"bar-max-target-q.txt",
117					],
118					max_target_p: [
119							"bar-max-target-p.txt",
120					],
121					max_target_o_low_priority: [
122							"bar-max-target-o-low-priority.txt",
123					],
124					blocked: [
125							"bar-blocked.txt",
126					],
127					unsupported_packages: [
128							"bar-unsupported-packages.txt",
129					],
130					split_packages: ["*"],
131				},
132			}
133
134			java_library {
135				name: "bar",
136				apex_available: ["myapex"],
137				srcs: ["a.java"],
138				system_modules: "none",
139				sdk_version: "none",
140				compile_dex: true,
141				permitted_packages: ["bar"],
142				min_sdk_version: "30", // R
143			}
144
145			java_sdk_library {
146				name: "foo",
147				srcs: ["a.java"],
148				public: {
149					enabled: true,
150				},
151				compile_dex: true,
152			}
153		`),
154	).RunTest(t)
155
156	pbcp := result.Module("platform-bootclasspath", "android_common")
157	info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
158
159	for _, category := range java.HiddenAPIFlagFileCategories {
160		name := category.PropertyName()
161		message := fmt.Sprintf("category %s", name)
162		filename := strings.ReplaceAll(name, "_", "-")
163		expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)}
164		android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
165	}
166
167	android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
168	android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
169	android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/index.csv"}, info.IndexPaths)
170
171	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())
172	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())
173}
174
175// TestPlatformBootclasspath_LegacyPrebuiltFragment verifies that the
176// prebuilt_bootclasspath_fragment falls back to using the complete stub-flags/all-flags if the
177// filtered files are not provided.
178//
179// TODO: Remove once all prebuilts use the filtered_... properties.
180func TestPlatformBootclasspath_LegacyPrebuiltFragment(t *testing.T) {
181	result := android.GroupFixturePreparers(
182		prepareForTestWithPlatformBootclasspath,
183		java.FixtureConfigureApexBootJars("myapex:foo"),
184		java.PrepareForTestWithJavaSdkLibraryFiles,
185	).RunTestWithBp(t, `
186		prebuilt_apex {
187			name: "myapex",
188			src: "myapex.apex",
189			exported_bootclasspath_fragments: ["mybootclasspath-fragment"],
190		}
191
192		// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
193		// because AlwaysUsePrebuiltSdks() is true.
194		java_sdk_library_import {
195			name: "foo",
196			prefer: false,
197			shared_library: false,
198			permitted_packages: ["foo"],
199			public: {
200				jars: ["sdk_library/public/foo-stubs.jar"],
201				stub_srcs: ["sdk_library/public/foo_stub_sources"],
202				current_api: "sdk_library/public/foo.txt",
203				removed_api: "sdk_library/public/foo-removed.txt",
204				sdk_version: "current",
205			},
206			apex_available: ["myapex"],
207		}
208
209		prebuilt_bootclasspath_fragment {
210			name: "mybootclasspath-fragment",
211			apex_available: [
212				"myapex",
213			],
214			contents: [
215				"foo",
216			],
217			hidden_api: {
218				stub_flags: "prebuilt-stub-flags.csv",
219				annotation_flags: "prebuilt-annotation-flags.csv",
220				metadata: "prebuilt-metadata.csv",
221				index: "prebuilt-index.csv",
222				all_flags: "prebuilt-all-flags.csv",
223			},
224		}
225
226		platform_bootclasspath {
227			name: "myplatform-bootclasspath",
228			fragments: [
229				{
230					apex: "myapex",
231					module:"mybootclasspath-fragment",
232				},
233			],
234		}
235`,
236	)
237
238	pbcp := result.Module("myplatform-bootclasspath", "android_common")
239	info, _ := android.SingletonModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider)
240
241	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())
242	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())
243}
244
245func TestPlatformBootclasspathDependencies(t *testing.T) {
246	result := android.GroupFixturePreparers(
247		prepareForTestWithPlatformBootclasspath,
248		prepareForTestWithArtApex,
249		prepareForTestWithMyapex,
250		// Configure some libraries in the art and framework boot images.
251		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo"),
252		java.FixtureConfigureApexBootJars("myapex:bar"),
253		java.PrepareForTestWithJavaSdkLibraryFiles,
254		java.FixtureWithLastReleaseApis("foo"),
255		java.PrepareForTestWithDexpreopt,
256		dexpreopt.FixtureDisableDexpreoptBootImages(false),
257		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
258			variables.BuildFlags = map[string]string{
259				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
260			}
261		}),
262	).RunTestWithBp(t, `
263		apex {
264			name: "com.android.art",
265			key: "com.android.art.key",
266 			bootclasspath_fragments: [
267				"art-bootclasspath-fragment",
268			],
269			updatable: false,
270		}
271
272		apex_key {
273			name: "com.android.art.key",
274			public_key: "com.android.art.avbpubkey",
275			private_key: "com.android.art.pem",
276		}
277
278		bootclasspath_fragment {
279			name: "art-bootclasspath-fragment",
280			image_name: "art",
281			apex_available: [
282				"com.android.art",
283			],
284			contents: [
285				"baz",
286				"quuz",
287			],
288			hidden_api: {
289				split_packages: ["*"],
290			},
291		}
292
293		java_library {
294			name: "baz",
295			apex_available: [
296				"com.android.art",
297			],
298			srcs: ["b.java"],
299			installable: true,
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}
417
418// TestPlatformBootclasspath_AlwaysUsePrebuiltSdks verifies that the build does not fail when
419// AlwaysUsePrebuiltSdk() returns true.
420func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
421	result := android.GroupFixturePreparers(
422		prepareForTestWithPlatformBootclasspath,
423		prepareForTestWithMyapex,
424		// Configure two libraries, the first is a java_sdk_library whose prebuilt will be used because
425		// of AlwaysUsePrebuiltsSdk(). The second is a normal library that is unaffected. The order
426		// matters, so that the dependencies resolved by the platform_bootclasspath matches the
427		// configured list.
428		java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
429		java.PrepareForTestWithJavaSdkLibraryFiles,
430		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
431			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
432			variables.BuildFlags = map[string]string{
433				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
434			}
435		}),
436		java.FixtureWithPrebuiltApis(map[string][]string{
437			"current": {},
438			"30":      {"foo"},
439		}),
440	).RunTestWithBp(t, `
441		apex {
442			name: "myapex",
443			key: "myapex.key",
444			bootclasspath_fragments: [
445				"mybootclasspath-fragment",
446			],
447			updatable: false,
448		}
449
450		apex_key {
451			name: "myapex.key",
452			public_key: "testkey.avbpubkey",
453			private_key: "testkey.pem",
454		}
455
456		java_library {
457			name: "bar",
458			srcs: ["b.java"],
459			installable: true,
460			apex_available: ["myapex"],
461			permitted_packages: ["bar"],
462		}
463
464		java_sdk_library {
465			name: "foo",
466			srcs: ["b.java"],
467			shared_library: false,
468			public: {
469				enabled: true,
470			},
471			apex_available: ["myapex"],
472			permitted_packages: ["foo"],
473		}
474
475		prebuilt_apex {
476			name: "myapex",
477			src: "myapex.apex",
478			exported_bootclasspath_fragments: ["mybootclasspath-fragment"],
479		}
480
481		// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
482		// because AlwaysUsePrebuiltSdks() is true.
483		java_sdk_library_import {
484			name: "foo",
485			prefer: false,
486			shared_library: false,
487			permitted_packages: ["foo"],
488			public: {
489				jars: ["sdk_library/public/foo-stubs.jar"],
490				stub_srcs: ["sdk_library/public/foo_stub_sources"],
491				current_api: "sdk_library/public/foo.txt",
492				removed_api: "sdk_library/public/foo-removed.txt",
493				sdk_version: "current",
494			},
495			apex_available: ["myapex"],
496		}
497
498		// This always depends on the source foo module, its dependencies are not affected by the
499		// AlwaysUsePrebuiltSdks().
500		bootclasspath_fragment {
501			name: "mybootclasspath-fragment",
502			apex_available: [
503				"myapex",
504			],
505			contents: [
506				"foo", "bar",
507			],
508			hidden_api: {
509				split_packages: ["*"],
510			},
511		}
512
513		prebuilt_bootclasspath_fragment {
514			name: "mybootclasspath-fragment",
515			apex_available: [
516				"myapex",
517			],
518			contents: [
519				"foo",
520			],
521			hidden_api: {
522				stub_flags: "",
523				annotation_flags: "",
524				metadata: "",
525				index: "",
526				all_flags: "",
527			},
528		}
529
530		platform_bootclasspath {
531			name: "myplatform-bootclasspath",
532			fragments: [
533				{
534					apex: "myapex",
535					module:"mybootclasspath-fragment",
536				},
537			],
538		}
539`,
540	)
541
542	java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
543		// The configured contents of BootJars.
544		"myapex:prebuilt_foo",
545		"myapex:bar",
546	})
547
548	// Make sure that the myplatform-bootclasspath has the correct dependencies.
549	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
550		// source vs prebuilt selection metadata module
551		`platform:all_apex_contributions`,
552
553		// The following are stubs.
554		"platform:prebuilt_sdk_public_current_android",
555		"platform:prebuilt_sdk_system_current_android",
556		"platform:prebuilt_sdk_test_current_android",
557
558		// Not a prebuilt as no prebuilt existed when it was added.
559		"platform:legacy.core.platform.api.stubs.exportable",
560
561		// The platform_bootclasspath intentionally adds dependencies on both source and prebuilt
562		// modules when available as it does not know which one will be preferred.
563		"myapex:foo",
564		"myapex:prebuilt_foo",
565
566		// Only a source module exists.
567		"myapex:bar",
568
569		// The fragments.
570		"myapex:mybootclasspath-fragment",
571		"myapex:prebuilt_mybootclasspath-fragment",
572	})
573}
574
575// CheckModuleDependencies checks the dependencies of the selected module against the expected list.
576//
577// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
578// name of the apex, or platform is it is not part of an apex and <module> is the module name.
579func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
580	t.Helper()
581	module := ctx.ModuleForTests(name, variant).Module()
582	modules := []android.Module{}
583	ctx.VisitDirectDeps(module, func(m blueprint.Module) {
584		modules = append(modules, m.(android.Module))
585	})
586
587	pairs := java.ApexNamePairsFromModules(ctx, modules)
588	android.AssertDeepEquals(t, "module dependencies", expected, pairs)
589}
590
591// TestPlatformBootclasspath_IncludesRemainingApexJars verifies that any apex boot jar is present in
592// platform_bootclasspath's classpaths.proto config, if the apex does not generate its own config
593// by setting generate_classpaths_proto property to false.
594func TestPlatformBootclasspath_IncludesRemainingApexJars(t *testing.T) {
595	result := android.GroupFixturePreparers(
596		prepareForTestWithPlatformBootclasspath,
597		prepareForTestWithMyapex,
598		java.FixtureConfigureApexBootJars("myapex:foo"),
599		android.FixtureWithRootAndroidBp(`
600			platform_bootclasspath {
601				name: "platform-bootclasspath",
602				fragments: [
603					{
604						apex: "myapex",
605						module:"foo-fragment",
606					},
607				],
608			}
609
610			apex {
611				name: "myapex",
612				key: "myapex.key",
613				bootclasspath_fragments: ["foo-fragment"],
614				updatable: false,
615			}
616
617			apex_key {
618				name: "myapex.key",
619				public_key: "testkey.avbpubkey",
620				private_key: "testkey.pem",
621			}
622
623			bootclasspath_fragment {
624				name: "foo-fragment",
625				generate_classpaths_proto: false,
626				contents: ["foo"],
627				apex_available: ["myapex"],
628				hidden_api: {
629					split_packages: ["*"],
630				},
631			}
632
633			java_library {
634				name: "foo",
635				srcs: ["a.java"],
636				system_modules: "none",
637				sdk_version: "none",
638				compile_dex: true,
639				apex_available: ["myapex"],
640				permitted_packages: ["foo"],
641			}
642		`),
643	).RunTest(t)
644
645	java.CheckClasspathFragmentProtoContentInfoProvider(t, result,
646		true,         // proto should be generated
647		"myapex:foo", // apex doesn't generate its own config, so must be in platform_bootclasspath
648		"bootclasspath.pb",
649		"out/soong/target/product/test_device/system/etc/classpaths",
650	)
651}
652
653func TestBootJarNotInApex(t *testing.T) {
654	android.GroupFixturePreparers(
655		prepareForTestWithPlatformBootclasspath,
656		PrepareForTestWithApexBuildComponents,
657		prepareForTestWithMyapex,
658		java.FixtureConfigureApexBootJars("myapex:foo"),
659	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
660		`dependency "foo" of "myplatform-bootclasspath" missing variant`)).
661		RunTestWithBp(t, `
662			apex {
663				name: "myapex",
664				key: "myapex.key",
665				updatable: false,
666			}
667
668			apex_key {
669				name: "myapex.key",
670				public_key: "testkey.avbpubkey",
671				private_key: "testkey.pem",
672			}
673
674			java_library {
675				name: "foo",
676				srcs: ["b.java"],
677				installable: true,
678				apex_available: [
679					"myapex",
680				],
681			}
682
683			bootclasspath_fragment {
684				name: "not-in-apex-fragment",
685				contents: [
686					"foo",
687				],
688				hidden_api: {
689					split_packages: ["*"],
690				},
691			}
692
693			platform_bootclasspath {
694				name: "myplatform-bootclasspath",
695			}
696		`)
697}
698
699func TestBootFragmentNotInApex(t *testing.T) {
700	android.GroupFixturePreparers(
701		prepareForTestWithPlatformBootclasspath,
702		PrepareForTestWithApexBuildComponents,
703		prepareForTestWithMyapex,
704		java.FixtureConfigureApexBootJars("myapex:foo"),
705	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
706		`library foo.*have no corresponding fragment.*`)).RunTestWithBp(t, `
707			apex {
708				name: "myapex",
709				key: "myapex.key",
710				java_libs: ["foo"],
711				updatable: false,
712			}
713
714			apex_key {
715				name: "myapex.key",
716				public_key: "testkey.avbpubkey",
717				private_key: "testkey.pem",
718			}
719
720			java_library {
721				name: "foo",
722				srcs: ["b.java"],
723				installable: true,
724				apex_available: ["myapex"],
725				permitted_packages: ["foo"],
726			}
727
728			bootclasspath_fragment {
729				name: "not-in-apex-fragment",
730				contents: ["foo"],
731				hidden_api: {
732					split_packages: ["*"],
733				},
734			}
735
736			platform_bootclasspath {
737				name: "myplatform-bootclasspath",
738			}
739		`)
740}
741
742func TestNonBootJarInFragment(t *testing.T) {
743	android.GroupFixturePreparers(
744		prepareForTestWithPlatformBootclasspath,
745		PrepareForTestWithApexBuildComponents,
746		prepareForTestWithMyapex,
747		java.FixtureConfigureApexBootJars("myapex:foo"),
748	).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
749		`in contents must also be declared in PRODUCT_APEX_BOOT_JARS`)).
750		RunTestWithBp(t, `
751			apex {
752				name: "myapex",
753				key: "myapex.key",
754				bootclasspath_fragments: ["apex-fragment"],
755				updatable: false,
756			}
757
758			apex_key {
759				name: "myapex.key",
760				public_key: "testkey.avbpubkey",
761				private_key: "testkey.pem",
762			}
763
764			java_library {
765				name: "foo",
766				srcs: ["b.java"],
767				installable: true,
768				apex_available: ["myapex"],
769				permitted_packages: ["foo"],
770			}
771
772			java_library {
773				name: "bar",
774				srcs: ["b.java"],
775				installable: true,
776				apex_available: ["myapex"],
777				permitted_packages: ["bar"],
778			}
779
780			bootclasspath_fragment {
781				name: "apex-fragment",
782				contents: ["foo", "bar"],
783				apex_available:[ "myapex" ],
784				hidden_api: {
785					split_packages: ["*"],
786				},
787			}
788
789			platform_bootclasspath {
790				name: "myplatform-bootclasspath",
791				fragments: [{
792						apex: "myapex",
793						module:"apex-fragment",
794				}],
795			}
796		`)
797}
798
799// Source and prebuilt apex provide different set of boot jars
800func TestNonBootJarMissingInPrebuiltFragment(t *testing.T) {
801	bp := `
802		apex {
803			name: "myapex",
804			key: "myapex.key",
805			bootclasspath_fragments: ["apex-fragment"],
806			updatable: false,
807		}
808
809		apex_key {
810			name: "myapex.key",
811			public_key: "testkey.avbpubkey",
812			private_key: "testkey.pem",
813		}
814
815		java_library {
816			name: "foo",
817			srcs: ["b.java"],
818			installable: true,
819			apex_available: ["myapex"],
820			permitted_packages: ["foo"],
821		}
822
823		java_library {
824			name: "bar",
825			srcs: ["b.java"],
826			installable: true,
827			apex_available: ["myapex"],
828			permitted_packages: ["bar"],
829		}
830
831		bootclasspath_fragment {
832			name: "apex-fragment",
833			contents: ["foo", "bar"],
834			apex_available:[ "myapex" ],
835			hidden_api: {
836				split_packages: ["*"],
837			},
838		}
839
840		prebuilt_apex {
841			name: "com.google.android.myapex", // mainline prebuilt selection logic in soong relies on the naming convention com.google.android
842			apex_name: "myapex",
843			source_apex_name: "myapex",
844			src: "myapex.apex",
845			exported_bootclasspath_fragments: ["apex-fragment"],
846		}
847
848		java_import {
849			name: "foo",
850			jars: ["foo.jar"],
851			apex_available: ["myapex"],
852			permitted_packages: ["foo"],
853		}
854
855		prebuilt_bootclasspath_fragment {
856			name: "apex-fragment",
857			contents: ["foo"], // Unlike the source fragment, this is missing bar
858			apex_available:[ "myapex" ],
859			hidden_api: {
860				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
861				metadata: "my-bootclasspath-fragment/metadata.csv",
862				index: "my-bootclasspath-fragment/index.csv",
863				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
864				all_flags: "my-bootclasspath-fragment/all-flags.csv",
865			},
866		}
867
868		// Another prebuilt apex, but this is not selected during the build.
869		prebuilt_apex {
870			name: "com.google.android.myapex.v2", // mainline prebuilt selection logic in soong relies on the naming convention com.google.android
871			apex_name: "myapex",
872			source_apex_name: "myapex",
873			src: "myapex.apex",
874			exported_bootclasspath_fragments: ["apex-fragment.v2"],
875		}
876
877		java_import {
878			name: "bar",
879			jars: ["bar.jar"],
880			apex_available: ["myapex"],
881			permitted_packages: ["bar"],
882		}
883
884		prebuilt_bootclasspath_fragment {
885			name: "apex-fragment.v2",
886			contents: ["bar"], // Unlike the source fragment, this is missing foo
887			apex_available:[ "myapex" ],
888			hidden_api: {
889				annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
890				metadata: "my-bootclasspath-fragment/metadata.csv",
891				index: "my-bootclasspath-fragment/index.csv",
892				stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
893				all_flags: "my-bootclasspath-fragment/all-flags.csv",
894			},
895		}
896
897
898		apex_contributions {
899			name: "my_apex_contributions",
900			api_domain: "myapex",
901			contents: [%v],
902		}
903	`
904	testCases := []struct {
905		desc                     string
906		configuredBootJars       []string
907		apexContributionContents string
908		errorExpected            bool
909	}{
910		{
911			desc:               "Source apex is selected, and APEX_BOOT_JARS is correctly configured for source apex builds",
912			configuredBootJars: []string{"myapex:foo", "myapex:bar"},
913		},
914		{
915			desc:               "Source apex is selected, and APEX_BOOT_JARS is missing bar",
916			configuredBootJars: []string{"myapex:foo"},
917			errorExpected:      true,
918		},
919		{
920			desc:                     "Prebuilt apex is selected, and APEX_BOOT_JARS is correctly configured for prebuilt apex build",
921			configuredBootJars:       []string{"myapex:foo"},
922			apexContributionContents: `"prebuilt_com.google.android.myapex"`,
923		},
924		{
925			desc:                     "Prebuilt apex is selected, and APEX_BOOT_JARS is missing foo",
926			configuredBootJars:       []string{"myapex:bar"},
927			apexContributionContents: `"prebuilt_com.google.android.myapex"`,
928			errorExpected:            true,
929		},
930	}
931
932	for _, tc := range testCases {
933		fixture := android.GroupFixturePreparers(
934			prepareForTestWithPlatformBootclasspath,
935			PrepareForTestWithApexBuildComponents,
936			prepareForTestWithMyapex,
937			java.FixtureConfigureApexBootJars(tc.configuredBootJars...),
938			android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
939				variables.BuildFlags = map[string]string{
940					"RELEASE_APEX_CONTRIBUTIONS_ART": "my_apex_contributions",
941				}
942			}),
943		)
944		if tc.errorExpected {
945			fixture = fixture.ExtendWithErrorHandler(
946				android.FixtureExpectsAtLeastOneErrorMatchingPattern(`in contents.*must also be declared in PRODUCT_APEX_BOOT_JARS`),
947			)
948		}
949		fixture.RunTestWithBp(t, fmt.Sprintf(bp, tc.apexContributionContents))
950	}
951}
952