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	"sort"
20	"strings"
21	"testing"
22
23	"android/soong/android"
24	"android/soong/java"
25	"github.com/google/blueprint/proptools"
26)
27
28// Contains tests for bootclasspath_fragment logic from java/bootclasspath_fragment.go as the ART
29// bootclasspath_fragment requires modules from the ART apex.
30
31var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers(
32	java.PrepareForTestWithDexpreopt,
33	PrepareForTestWithApexBuildComponents,
34)
35
36// Some additional files needed for the art apex.
37var prepareForTestWithArtApex = android.FixtureMergeMockFs(android.MockFS{
38	"com.android.art.avbpubkey":                          nil,
39	"com.android.art.pem":                                nil,
40	"system/sepolicy/apex/com.android.art-file_contexts": nil,
41})
42
43func TestBootclasspathFragments(t *testing.T) {
44	result := android.GroupFixturePreparers(
45		prepareForTestWithBootclasspathFragment,
46		// Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath.
47		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
48		prepareForTestWithArtApex,
49
50		java.PrepareForTestWithJavaSdkLibraryFiles,
51		java.FixtureWithLastReleaseApis("foo"),
52	).RunTestWithBp(t, `
53		java_sdk_library {
54			name: "foo",
55			srcs: ["b.java"],
56		}
57
58		java_library {
59			name: "bar",
60			srcs: ["b.java"],
61			installable: true,
62		}
63
64		apex {
65			name: "com.android.art",
66			key: "com.android.art.key",
67			bootclasspath_fragments: ["art-bootclasspath-fragment"],
68 			java_libs: [
69				"baz",
70				"quuz",
71			],
72			updatable: false,
73		}
74
75		apex_key {
76			name: "com.android.art.key",
77			public_key: "com.android.art.avbpubkey",
78			private_key: "com.android.art.pem",
79		}
80
81		java_library {
82			name: "baz",
83			apex_available: [
84				"com.android.art",
85			],
86			srcs: ["b.java"],
87			compile_dex: true,
88		}
89
90		java_library {
91			name: "quuz",
92			apex_available: [
93				"com.android.art",
94			],
95			srcs: ["b.java"],
96			compile_dex: true,
97		}
98
99		bootclasspath_fragment {
100			name: "art-bootclasspath-fragment",
101			image_name: "art",
102			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
103			contents: ["baz", "quuz"],
104			apex_available: [
105				"com.android.art",
106			],
107		}
108`,
109	)
110
111	// Make sure that the art-bootclasspath-fragment is using the correct configuration.
112	checkBootclasspathFragment(t, result, "art-bootclasspath-fragment", "android_common_apex10000",
113		"com.android.art:baz,com.android.art:quuz", `
114test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.art
115test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.oat
116test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot.vdex
117test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-quuz.art
118test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-quuz.oat
119test_device/dex_artjars/android/apex/art_boot_images/javalib/arm/boot-quuz.vdex
120test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.art
121test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.oat
122test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot.vdex
123test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-quuz.art
124test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-quuz.oat
125test_device/dex_artjars/android/apex/art_boot_images/javalib/arm64/boot-quuz.vdex
126`)
127}
128
129func TestBootclasspathFragments_FragmentDependency(t *testing.T) {
130	result := android.GroupFixturePreparers(
131		prepareForTestWithBootclasspathFragment,
132		// Configure some libraries in the art bootclasspath_fragment and platform_bootclasspath.
133		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo", "platform:bar"),
134		prepareForTestWithArtApex,
135
136		java.PrepareForTestWithJavaSdkLibraryFiles,
137		java.FixtureWithLastReleaseApis("foo", "baz"),
138	).RunTestWithBp(t, `
139		java_sdk_library {
140			name: "foo",
141			srcs: ["b.java"],
142			shared_library: false,
143			public: {
144				enabled: true,
145			},
146			system: {
147				enabled: true,
148			},
149		}
150
151		java_library {
152			name: "bar",
153			srcs: ["b.java"],
154			installable: true,
155		}
156
157		apex {
158			name: "com.android.art",
159			key: "com.android.art.key",
160			bootclasspath_fragments: ["art-bootclasspath-fragment"],
161			updatable: false,
162		}
163
164		apex_key {
165			name: "com.android.art.key",
166			public_key: "com.android.art.avbpubkey",
167			private_key: "com.android.art.pem",
168		}
169
170		java_sdk_library {
171			name: "baz",
172			apex_available: [
173				"com.android.art",
174			],
175			srcs: ["b.java"],
176			shared_library: false,
177			public: {
178				enabled: true,
179			},
180			system: {
181				enabled: true,
182			},
183			test: {
184				enabled: true,
185			},
186		}
187
188		java_library {
189			name: "quuz",
190			apex_available: [
191				"com.android.art",
192			],
193			srcs: ["b.java"],
194			compile_dex: true,
195		}
196
197		bootclasspath_fragment {
198			name: "art-bootclasspath-fragment",
199			image_name: "art",
200			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
201			contents: ["baz", "quuz"],
202			apex_available: [
203				"com.android.art",
204			],
205		}
206
207		bootclasspath_fragment {
208			name: "other-bootclasspath-fragment",
209			contents: ["foo", "bar"],
210			fragments: [
211					{
212							apex: "com.android.art",
213							module: "art-bootclasspath-fragment",
214					},
215			],
216		}
217`,
218	)
219
220	checkAPIScopeStubs := func(message string, info java.HiddenAPIInfo, apiScope *java.HiddenAPIScope, expectedPaths ...string) {
221		t.Helper()
222		paths := info.TransitiveStubDexJarsByScope.StubDexJarsForScope(apiScope)
223		android.AssertPathsRelativeToTopEquals(t, fmt.Sprintf("%s %s", message, apiScope), expectedPaths, paths)
224	}
225
226	// Check stub dex paths exported by art.
227	artFragment := result.Module("art-bootclasspath-fragment", "android_common")
228	artInfo := result.ModuleProvider(artFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
229
230	bazPublicStubs := "out/soong/.intermediates/baz.stubs/android_common/dex/baz.stubs.jar"
231	bazSystemStubs := "out/soong/.intermediates/baz.stubs.system/android_common/dex/baz.stubs.system.jar"
232	bazTestStubs := "out/soong/.intermediates/baz.stubs.test/android_common/dex/baz.stubs.test.jar"
233
234	checkAPIScopeStubs("art", artInfo, java.PublicHiddenAPIScope, bazPublicStubs)
235	checkAPIScopeStubs("art", artInfo, java.SystemHiddenAPIScope, bazSystemStubs)
236	checkAPIScopeStubs("art", artInfo, java.TestHiddenAPIScope, bazTestStubs)
237	checkAPIScopeStubs("art", artInfo, java.CorePlatformHiddenAPIScope)
238
239	// Check stub dex paths exported by other.
240	otherFragment := result.Module("other-bootclasspath-fragment", "android_common")
241	otherInfo := result.ModuleProvider(otherFragment, java.HiddenAPIInfoProvider).(java.HiddenAPIInfo)
242
243	fooPublicStubs := "out/soong/.intermediates/foo.stubs/android_common/dex/foo.stubs.jar"
244	fooSystemStubs := "out/soong/.intermediates/foo.stubs.system/android_common/dex/foo.stubs.system.jar"
245
246	checkAPIScopeStubs("other", otherInfo, java.PublicHiddenAPIScope, bazPublicStubs, fooPublicStubs)
247	checkAPIScopeStubs("other", otherInfo, java.SystemHiddenAPIScope, bazSystemStubs, fooSystemStubs)
248	checkAPIScopeStubs("other", otherInfo, java.TestHiddenAPIScope, bazTestStubs, fooSystemStubs)
249	checkAPIScopeStubs("other", otherInfo, java.CorePlatformHiddenAPIScope)
250}
251
252func checkBootclasspathFragment(t *testing.T, result *android.TestResult, moduleName, variantName string, expectedConfiguredModules string, expectedBootclasspathFragmentFiles string) {
253	t.Helper()
254
255	bootclasspathFragment := result.ModuleForTests(moduleName, variantName).Module().(*java.BootclasspathFragmentModule)
256
257	bootclasspathFragmentInfo := result.ModuleProvider(bootclasspathFragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
258	modules := bootclasspathFragmentInfo.Modules()
259	android.AssertStringEquals(t, "invalid modules for "+moduleName, expectedConfiguredModules, modules.String())
260
261	// Get a list of all the paths in the boot image sorted by arch type.
262	allPaths := []string{}
263	bootImageFilesByArchType := bootclasspathFragmentInfo.AndroidBootImageFilesByArchType()
264	for _, archType := range android.ArchTypeList() {
265		if paths, ok := bootImageFilesByArchType[archType]; ok {
266			for _, path := range paths {
267				allPaths = append(allPaths, android.NormalizePathForTesting(path))
268			}
269		}
270	}
271
272	android.AssertTrimmedStringEquals(t, "invalid paths for "+moduleName, expectedBootclasspathFragmentFiles, strings.Join(allPaths, "\n"))
273}
274
275func TestBootclasspathFragmentInArtApex(t *testing.T) {
276	commonPreparer := android.GroupFixturePreparers(
277		prepareForTestWithBootclasspathFragment,
278		prepareForTestWithArtApex,
279
280		android.FixtureWithRootAndroidBp(`
281		apex {
282			name: "com.android.art",
283			key: "com.android.art.key",
284			bootclasspath_fragments: [
285				"mybootclasspathfragment",
286			],
287			// bar (like foo) should be transitively included in this apex because it is part of the
288			// mybootclasspathfragment bootclasspath_fragment. However, it is kept here to ensure that the
289			// apex dedups the files correctly.
290			java_libs: [
291				"bar",
292			],
293			updatable: false,
294		}
295
296		apex_key {
297			name: "com.android.art.key",
298			public_key: "testkey.avbpubkey",
299			private_key: "testkey.pem",
300		}
301
302		java_library {
303			name: "foo",
304			srcs: ["b.java"],
305			installable: true,
306			apex_available: [
307				"com.android.art",
308			],
309		}
310
311		java_library {
312			name: "bar",
313			srcs: ["b.java"],
314			installable: true,
315			apex_available: [
316				"com.android.art",
317			],
318		}
319
320		java_import {
321			name: "foo",
322			jars: ["foo.jar"],
323			apex_available: [
324				"com.android.art",
325			],
326			compile_dex: true,
327		}
328
329		java_import {
330			name: "bar",
331			jars: ["bar.jar"],
332			apex_available: [
333				"com.android.art",
334			],
335			compile_dex: true,
336		}
337	`),
338	)
339
340	contentsInsert := func(contents []string) string {
341		insert := ""
342		if contents != nil {
343			insert = fmt.Sprintf(`contents: ["%s"],`, strings.Join(contents, `", "`))
344		}
345		return insert
346	}
347
348	addSource := func(contents ...string) android.FixturePreparer {
349		text := fmt.Sprintf(`
350			bootclasspath_fragment {
351				name: "mybootclasspathfragment",
352				image_name: "art",
353				%s
354				apex_available: [
355					"com.android.art",
356				],
357			}
358		`, contentsInsert(contents))
359
360		return android.FixtureAddTextFile("art/build/boot/Android.bp", text)
361	}
362
363	addPrebuilt := func(prefer bool, contents ...string) android.FixturePreparer {
364		text := fmt.Sprintf(`
365			prebuilt_apex {
366				name: "com.android.art",
367				arch: {
368					arm64: {
369						src: "com.android.art-arm64.apex",
370					},
371					arm: {
372						src: "com.android.art-arm.apex",
373					},
374				},
375				exported_bootclasspath_fragments: ["mybootclasspathfragment"],
376			}
377
378			prebuilt_bootclasspath_fragment {
379				name: "mybootclasspathfragment",
380				image_name: "art",
381				%s
382				prefer: %t,
383				apex_available: [
384					"com.android.art",
385				],
386			}
387		`, contentsInsert(contents), prefer)
388		return android.FixtureAddTextFile("prebuilts/module_sdk/art/Android.bp", text)
389	}
390
391	t.Run("boot image files from source", func(t *testing.T) {
392		result := android.GroupFixturePreparers(
393			commonPreparer,
394
395			// Configure some libraries in the art bootclasspath_fragment that match the source
396			// bootclasspath_fragment's contents property.
397			java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
398			addSource("foo", "bar"),
399		).RunTest(t)
400
401		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
402			"etc/classpaths/bootclasspath.pb",
403			"javalib/arm/boot.art",
404			"javalib/arm/boot.oat",
405			"javalib/arm/boot.vdex",
406			"javalib/arm/boot-bar.art",
407			"javalib/arm/boot-bar.oat",
408			"javalib/arm/boot-bar.vdex",
409			"javalib/arm64/boot.art",
410			"javalib/arm64/boot.oat",
411			"javalib/arm64/boot.vdex",
412			"javalib/arm64/boot-bar.art",
413			"javalib/arm64/boot-bar.oat",
414			"javalib/arm64/boot-bar.vdex",
415			"javalib/bar.jar",
416			"javalib/foo.jar",
417		})
418
419		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
420			`bar`,
421			`com.android.art.key`,
422			`mybootclasspathfragment`,
423		})
424
425		// Make sure that the source bootclasspath_fragment copies its dex files to the predefined
426		// locations for the art image.
427		module := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
428		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
429	})
430
431	t.Run("boot image files with preferred prebuilt", func(t *testing.T) {
432		result := android.GroupFixturePreparers(
433			commonPreparer,
434
435			// Configure some libraries in the art bootclasspath_fragment that match the source
436			// bootclasspath_fragment's contents property.
437			java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
438			addSource("foo", "bar"),
439
440			// Make sure that a preferred prebuilt with consistent contents doesn't affect the apex.
441			addPrebuilt(true, "foo", "bar"),
442		).RunTest(t)
443
444		ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
445			"etc/classpaths/bootclasspath.pb",
446			"javalib/arm/boot.art",
447			"javalib/arm/boot.oat",
448			"javalib/arm/boot.vdex",
449			"javalib/arm/boot-bar.art",
450			"javalib/arm/boot-bar.oat",
451			"javalib/arm/boot-bar.vdex",
452			"javalib/arm64/boot.art",
453			"javalib/arm64/boot.oat",
454			"javalib/arm64/boot.vdex",
455			"javalib/arm64/boot-bar.art",
456			"javalib/arm64/boot-bar.oat",
457			"javalib/arm64/boot-bar.vdex",
458			"javalib/bar.jar",
459			"javalib/foo.jar",
460		})
461
462		java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
463			`bar`,
464			`com.android.art.key`,
465			`mybootclasspathfragment`,
466			`prebuilt_com.android.art`,
467		})
468
469		// Make sure that the prebuilt bootclasspath_fragment copies its dex files to the predefined
470		// locations for the art image.
471		module := result.ModuleForTests("prebuilt_mybootclasspathfragment", "android_common_com.android.art")
472		checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
473	})
474
475	t.Run("source with inconsistency between config and contents", func(t *testing.T) {
476		android.GroupFixturePreparers(
477			commonPreparer,
478
479			// Create an inconsistency between the ArtApexJars configuration and the art source
480			// bootclasspath_fragment module's contents property.
481			java.FixtureConfigureBootJars("com.android.art:foo"),
482			addSource("foo", "bar"),
483		).
484			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\QArtApexJars configuration specifies []string{"foo"}, contents property specifies []string{"foo", "bar"}\E`)).
485			RunTest(t)
486	})
487
488	t.Run("prebuilt with inconsistency between config and contents", func(t *testing.T) {
489		android.GroupFixturePreparers(
490			commonPreparer,
491
492			// Create an inconsistency between the ArtApexJars configuration and the art
493			// prebuilt_bootclasspath_fragment module's contents property.
494			java.FixtureConfigureBootJars("com.android.art:foo"),
495			addPrebuilt(false, "foo", "bar"),
496		).
497			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\QArtApexJars configuration specifies []string{"foo"}, contents property specifies []string{"foo", "bar"}\E`)).
498			RunTest(t)
499	})
500
501	t.Run("preferred prebuilt with inconsistency between config and contents", func(t *testing.T) {
502		android.GroupFixturePreparers(
503			commonPreparer,
504
505			// Create an inconsistency between the ArtApexJars configuration and the art
506			// prebuilt_bootclasspath_fragment module's contents property.
507			java.FixtureConfigureBootJars("com.android.art:foo"),
508			addPrebuilt(true, "foo", "bar"),
509
510			// Source contents property is consistent with the config.
511			addSource("foo"),
512		).
513			ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\QArtApexJars configuration specifies []string{"foo"}, contents property specifies []string{"foo", "bar"}\E`)).
514			RunTest(t)
515	})
516
517	t.Run("source preferred and prebuilt with inconsistency between config and contents", func(t *testing.T) {
518		android.GroupFixturePreparers(
519			commonPreparer,
520
521			// Create an inconsistency between the ArtApexJars configuration and the art
522			// prebuilt_bootclasspath_fragment module's contents property.
523			java.FixtureConfigureBootJars("com.android.art:foo"),
524			addPrebuilt(false, "foo", "bar"),
525
526			// Source contents property is consistent with the config.
527			addSource("foo"),
528
529			// This should pass because while the prebuilt is inconsistent with the configuration it is
530			// not actually used.
531		).RunTest(t)
532	})
533}
534
535func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) {
536	result := android.GroupFixturePreparers(
537		prepareForTestWithBootclasspathFragment,
538		prepareForTestWithArtApex,
539
540		android.FixtureMergeMockFs(android.MockFS{
541			"com.android.art-arm64.apex": nil,
542			"com.android.art-arm.apex":   nil,
543		}),
544
545		// Configure some libraries in the art bootclasspath_fragment.
546		java.FixtureConfigureBootJars("com.android.art:foo", "com.android.art:bar"),
547	).RunTestWithBp(t, `
548		prebuilt_apex {
549			name: "com.android.art",
550			arch: {
551				arm64: {
552					src: "com.android.art-arm64.apex",
553				},
554				arm: {
555					src: "com.android.art-arm.apex",
556				},
557			},
558			exported_bootclasspath_fragments: ["mybootclasspathfragment"],
559		}
560
561		java_import {
562			name: "foo",
563			jars: ["foo.jar"],
564			apex_available: [
565				"com.android.art",
566			],
567		}
568
569		java_import {
570			name: "bar",
571			jars: ["bar.jar"],
572			apex_available: [
573				"com.android.art",
574			],
575		}
576
577		prebuilt_bootclasspath_fragment {
578			name: "mybootclasspathfragment",
579			image_name: "art",
580			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
581			contents: ["foo", "bar"],
582			apex_available: [
583				"com.android.art",
584			],
585		}
586	`)
587
588	java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{
589		`com.android.art.apex.selector`,
590		`prebuilt_mybootclasspathfragment`,
591	})
592
593	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_com.android.art", []string{
594		`com.android.art.deapexer`,
595		`dex2oatd`,
596		`prebuilt_bar`,
597		`prebuilt_foo`,
598	})
599
600	module := result.ModuleForTests("mybootclasspathfragment", "android_common_com.android.art")
601	checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo")
602}
603
604// checkCopiesToPredefinedLocationForArt checks that the supplied modules are copied to the
605// predefined locations of boot dex jars used as inputs for the ART boot image.
606func checkCopiesToPredefinedLocationForArt(t *testing.T, config android.Config, module android.TestingModule, modules ...string) {
607	t.Helper()
608	bootJarLocations := []string{}
609	for _, output := range module.AllOutputs() {
610		output = android.StringRelativeToTop(config, output)
611		if strings.HasPrefix(output, "out/soong/test_device/dex_artjars_input/") {
612			bootJarLocations = append(bootJarLocations, output)
613		}
614	}
615
616	sort.Strings(bootJarLocations)
617	expected := []string{}
618	for _, m := range modules {
619		expected = append(expected, fmt.Sprintf("out/soong/test_device/dex_artjars_input/%s.jar", m))
620	}
621	sort.Strings(expected)
622
623	android.AssertArrayString(t, "copies to predefined locations for art", expected, bootJarLocations)
624}
625
626func TestBootclasspathFragmentContentsNoName(t *testing.T) {
627	result := android.GroupFixturePreparers(
628		prepareForTestWithBootclasspathFragment,
629		prepareForTestWithMyapex,
630		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
631		java.FixtureConfigureBootJars("myapex:foo", "myapex:bar"),
632		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
633		// is disabled.
634		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
635
636		java.PrepareForTestWithJavaSdkLibraryFiles,
637		java.FixtureWithLastReleaseApis("foo"),
638	).RunTestWithBp(t, `
639		apex {
640			name: "myapex",
641			key: "myapex.key",
642			bootclasspath_fragments: [
643				"mybootclasspathfragment",
644			],
645			updatable: false,
646		}
647
648		apex_key {
649			name: "myapex.key",
650			public_key: "testkey.avbpubkey",
651			private_key: "testkey.pem",
652		}
653
654		java_sdk_library {
655			name: "foo",
656			srcs: ["b.java"],
657			shared_library: false,
658			public: {enabled: true},
659			apex_available: [
660				"myapex",
661			],
662		}
663
664		java_library {
665			name: "bar",
666			srcs: ["b.java"],
667			installable: true,
668			apex_available: [
669				"myapex",
670			],
671		}
672
673		bootclasspath_fragment {
674			name: "mybootclasspathfragment",
675			contents: [
676				"foo",
677				"bar",
678			],
679			apex_available: [
680				"myapex",
681			],
682		}
683	`)
684
685	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
686		// This does not include art, oat or vdex files as they are only included for the art boot
687		// image.
688		"etc/classpaths/bootclasspath.pb",
689		"javalib/bar.jar",
690		"javalib/foo.jar",
691	})
692
693	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
694		`myapex.key`,
695		`mybootclasspathfragment`,
696	})
697
698	apex := result.ModuleForTests("myapex", "android_common_myapex_image")
699	apexRule := apex.Rule("apexRule")
700	copyCommands := apexRule.Args["copy_commands"]
701
702	// Make sure that the fragment provides the hidden API encoded dex jars to the APEX.
703	fragment := result.Module("mybootclasspathfragment", "android_common_apex10000")
704
705	info := result.ModuleProvider(fragment, java.BootclasspathFragmentApexContentInfoProvider).(java.BootclasspathFragmentApexContentInfo)
706
707	checkFragmentExportedDexJar := func(name string, expectedDexJar string) {
708		module := result.Module(name, "android_common_apex10000")
709		dexJar, err := info.DexBootJarPathForContentModule(module)
710		if err != nil {
711			t.Error(err)
712		}
713		android.AssertPathRelativeToTopEquals(t, name+" dex", expectedDexJar, dexJar)
714
715		expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex_image/image.apex/javalib/%s.jar", expectedDexJar, name)
716		android.AssertStringDoesContain(t, name+" apex copy command", copyCommands, expectedCopyCommand)
717	}
718
719	checkFragmentExportedDexJar("foo", "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/hiddenapi-modular/encoded/foo.jar")
720	checkFragmentExportedDexJar("bar", "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/hiddenapi-modular/encoded/bar.jar")
721}
722
723func getDexJarPath(result *android.TestResult, name string) string {
724	module := result.Module(name, "android_common")
725	return module.(java.UsesLibraryDependency).DexJarBuildPath().RelativeToTop().String()
726}
727
728// TestBootclasspathFragment_HiddenAPIList checks to make sure that the correct parameters are
729// passed to the hiddenapi list tool.
730func TestBootclasspathFragment_HiddenAPIList(t *testing.T) {
731	result := android.GroupFixturePreparers(
732		prepareForTestWithBootclasspathFragment,
733		prepareForTestWithArtApex,
734		prepareForTestWithMyapex,
735		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
736		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz"),
737		java.FixtureConfigureUpdatableBootJars("myapex:foo", "myapex:bar"),
738		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
739		// is disabled.
740		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
741
742		java.PrepareForTestWithJavaSdkLibraryFiles,
743		java.FixtureWithLastReleaseApis("foo", "quuz"),
744	).RunTestWithBp(t, `
745		apex {
746			name: "com.android.art",
747			key: "com.android.art.key",
748			bootclasspath_fragments: ["art-bootclasspath-fragment"],
749			updatable: false,
750		}
751
752		apex_key {
753			name: "com.android.art.key",
754			public_key: "com.android.art.avbpubkey",
755			private_key: "com.android.art.pem",
756		}
757
758		java_library {
759			name: "baz",
760			apex_available: [
761				"com.android.art",
762			],
763			srcs: ["b.java"],
764			compile_dex: true,
765		}
766
767		java_sdk_library {
768			name: "quuz",
769			apex_available: [
770				"com.android.art",
771			],
772			srcs: ["b.java"],
773			compile_dex: true,
774			public: {enabled: true},
775			system: {enabled: true},
776			test: {enabled: true},
777			module_lib: {enabled: true},
778		}
779
780		bootclasspath_fragment {
781			name: "art-bootclasspath-fragment",
782			image_name: "art",
783			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
784			contents: ["baz", "quuz"],
785			apex_available: [
786				"com.android.art",
787			],
788		}
789
790		apex {
791			name: "myapex",
792			key: "myapex.key",
793			bootclasspath_fragments: [
794				"mybootclasspathfragment",
795			],
796			updatable: false,
797		}
798
799		apex_key {
800			name: "myapex.key",
801			public_key: "testkey.avbpubkey",
802			private_key: "testkey.pem",
803		}
804
805		java_sdk_library {
806			name: "foo",
807			srcs: ["b.java"],
808			shared_library: false,
809			public: {enabled: true},
810			apex_available: [
811				"myapex",
812			],
813		}
814
815		java_library {
816			name: "bar",
817			srcs: ["b.java"],
818			installable: true,
819			apex_available: [
820				"myapex",
821			],
822		}
823
824		bootclasspath_fragment {
825			name: "mybootclasspathfragment",
826			contents: [
827				"foo",
828				"bar",
829			],
830			apex_available: [
831				"myapex",
832			],
833			fragments: [
834				{
835					apex: "com.android.art",
836					module: "art-bootclasspath-fragment",
837				},
838			],
839		}
840	`)
841
842	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
843		"art-bootclasspath-fragment",
844		"bar",
845		"dex2oatd",
846		"foo",
847	})
848
849	fooStubs := getDexJarPath(result, "foo.stubs")
850	quuzPublicStubs := getDexJarPath(result, "quuz.stubs")
851	quuzSystemStubs := getDexJarPath(result, "quuz.stubs.system")
852	quuzTestStubs := getDexJarPath(result, "quuz.stubs.test")
853	quuzModuleLibStubs := getDexJarPath(result, "quuz.stubs.module_lib")
854
855	// Make sure that the fragment uses the quuz stub dex jars when generating the hidden API flags.
856	fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
857
858	rule := fragment.Rule("modularHiddenAPIStubFlagsFile")
859	command := rule.RuleParams.Command
860	android.AssertStringDoesContain(t, "check correct rule", command, "hiddenapi list")
861
862	// Make sure that the quuz stubs are available for resolving references from the implementation
863	// boot dex jars provided by this module.
864	android.AssertStringDoesContain(t, "quuz widest", command, "--dependency-stub-dex="+quuzModuleLibStubs)
865
866	// Make sure that the quuz stubs are available for resolving references from the different API
867	// stubs provided by this module.
868	android.AssertStringDoesContain(t, "public", command, "--public-stub-classpath="+quuzPublicStubs+":"+fooStubs)
869	android.AssertStringDoesContain(t, "system", command, "--system-stub-classpath="+quuzSystemStubs+":"+fooStubs)
870	android.AssertStringDoesContain(t, "test", command, "--test-stub-classpath="+quuzTestStubs+":"+fooStubs)
871}
872
873// TestBootclasspathFragment_AndroidNonUpdatable checks to make sure that setting
874// additional_stubs: ["android-non-updatable"] causes the source android-non-updatable modules to be
875// added to the hiddenapi list tool.
876func TestBootclasspathFragment_AndroidNonUpdatable(t *testing.T) {
877	result := android.GroupFixturePreparers(
878		prepareForTestWithBootclasspathFragment,
879		prepareForTestWithArtApex,
880		prepareForTestWithMyapex,
881		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
882		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "myapex:foo", "myapex:bar"),
883		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
884		// is disabled.
885		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
886
887		java.PrepareForTestWithJavaSdkLibraryFiles,
888		java.FixtureWithLastReleaseApis("foo", "android-non-updatable"),
889	).RunTestWithBp(t, `
890		java_sdk_library {
891			name: "android-non-updatable",
892			srcs: ["b.java"],
893			compile_dex: true,
894			public: {
895				enabled: true,
896			},
897			system: {
898				enabled: true,
899			},
900			test: {
901				enabled: true,
902			},
903			module_lib: {
904				enabled: true,
905			},
906		}
907
908		apex {
909			name: "com.android.art",
910			key: "com.android.art.key",
911			bootclasspath_fragments: ["art-bootclasspath-fragment"],
912 			java_libs: [
913				"baz",
914				"quuz",
915			],
916			updatable: false,
917		}
918
919		apex_key {
920			name: "com.android.art.key",
921			public_key: "com.android.art.avbpubkey",
922			private_key: "com.android.art.pem",
923		}
924
925		java_library {
926			name: "baz",
927			apex_available: [
928				"com.android.art",
929			],
930			srcs: ["b.java"],
931			compile_dex: true,
932		}
933
934		java_library {
935			name: "quuz",
936			apex_available: [
937				"com.android.art",
938			],
939			srcs: ["b.java"],
940			compile_dex: true,
941		}
942
943		bootclasspath_fragment {
944			name: "art-bootclasspath-fragment",
945			image_name: "art",
946			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
947			contents: ["baz", "quuz"],
948			apex_available: [
949				"com.android.art",
950			],
951		}
952
953		apex {
954			name: "myapex",
955			key: "myapex.key",
956			bootclasspath_fragments: [
957				"mybootclasspathfragment",
958			],
959			updatable: false,
960		}
961
962		apex_key {
963			name: "myapex.key",
964			public_key: "testkey.avbpubkey",
965			private_key: "testkey.pem",
966		}
967
968		java_sdk_library {
969			name: "foo",
970			srcs: ["b.java"],
971			shared_library: false,
972			public: {enabled: true},
973			apex_available: [
974				"myapex",
975			],
976		}
977
978		java_library {
979			name: "bar",
980			srcs: ["b.java"],
981			installable: true,
982			apex_available: [
983				"myapex",
984			],
985		}
986
987		bootclasspath_fragment {
988			name: "mybootclasspathfragment",
989			contents: [
990				"foo",
991				"bar",
992			],
993			apex_available: [
994				"myapex",
995			],
996			additional_stubs: ["android-non-updatable"],
997			fragments: [
998				{
999					apex: "com.android.art",
1000					module: "art-bootclasspath-fragment",
1001				},
1002			],
1003		}
1004	`)
1005
1006	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
1007		"android-non-updatable.stubs",
1008		"android-non-updatable.stubs.module_lib",
1009		"android-non-updatable.stubs.system",
1010		"android-non-updatable.stubs.test",
1011		"art-bootclasspath-fragment",
1012		"bar",
1013		"dex2oatd",
1014		"foo",
1015	})
1016
1017	nonUpdatablePublicStubs := getDexJarPath(result, "android-non-updatable.stubs")
1018	nonUpdatableSystemStubs := getDexJarPath(result, "android-non-updatable.stubs.system")
1019	nonUpdatableTestStubs := getDexJarPath(result, "android-non-updatable.stubs.test")
1020	nonUpdatableModuleLibStubs := getDexJarPath(result, "android-non-updatable.stubs.module_lib")
1021
1022	// Make sure that the fragment uses the android-non-updatable modules when generating the hidden
1023	// API flags.
1024	fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
1025
1026	rule := fragment.Rule("modularHiddenAPIStubFlagsFile")
1027	command := rule.RuleParams.Command
1028	android.AssertStringDoesContain(t, "check correct rule", command, "hiddenapi list")
1029
1030	// Make sure that the module_lib non-updatable stubs are available for resolving references from
1031	// the implementation boot dex jars provided by this module.
1032	android.AssertStringDoesContain(t, "android-non-updatable widest", command, "--dependency-stub-dex="+nonUpdatableModuleLibStubs)
1033
1034	// Make sure that the appropriate non-updatable stubs are available for resolving references from
1035	// the different API stubs provided by this module.
1036	android.AssertStringDoesContain(t, "public", command, "--public-stub-classpath="+nonUpdatablePublicStubs)
1037	android.AssertStringDoesContain(t, "system", command, "--system-stub-classpath="+nonUpdatableSystemStubs)
1038	android.AssertStringDoesContain(t, "test", command, "--test-stub-classpath="+nonUpdatableTestStubs)
1039}
1040
1041// TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks checks to make sure that
1042// setting additional_stubs: ["android-non-updatable"] causes the prebuilt android-non-updatable
1043// modules to be added to the hiddenapi list tool.
1044func TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks(t *testing.T) {
1045	result := android.GroupFixturePreparers(
1046		prepareForTestWithBootclasspathFragment,
1047		java.PrepareForTestWithJavaDefaultModules,
1048		prepareForTestWithArtApex,
1049		prepareForTestWithMyapex,
1050		// Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
1051		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "myapex:foo", "myapex:bar"),
1052		// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
1053		// is disabled.
1054		android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
1055
1056		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
1057			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
1058		}),
1059
1060		java.PrepareForTestWithJavaSdkLibraryFiles,
1061		java.FixtureWithPrebuiltApis(map[string][]string{
1062			"current": {"android-non-updatable"},
1063			"30":      {"foo"},
1064		}),
1065	).RunTestWithBp(t, `
1066		apex {
1067			name: "com.android.art",
1068			key: "com.android.art.key",
1069			bootclasspath_fragments: ["art-bootclasspath-fragment"],
1070 			java_libs: [
1071				"baz",
1072				"quuz",
1073			],
1074			updatable: false,
1075		}
1076
1077		apex_key {
1078			name: "com.android.art.key",
1079			public_key: "com.android.art.avbpubkey",
1080			private_key: "com.android.art.pem",
1081		}
1082
1083		java_library {
1084			name: "baz",
1085			apex_available: [
1086				"com.android.art",
1087			],
1088			srcs: ["b.java"],
1089			compile_dex: true,
1090		}
1091
1092		java_library {
1093			name: "quuz",
1094			apex_available: [
1095				"com.android.art",
1096			],
1097			srcs: ["b.java"],
1098			compile_dex: true,
1099		}
1100
1101		bootclasspath_fragment {
1102			name: "art-bootclasspath-fragment",
1103			image_name: "art",
1104			// Must match the "com.android.art:" entries passed to FixtureConfigureBootJars above.
1105			contents: ["baz", "quuz"],
1106			apex_available: [
1107				"com.android.art",
1108			],
1109		}
1110
1111		apex {
1112			name: "myapex",
1113			key: "myapex.key",
1114			bootclasspath_fragments: [
1115				"mybootclasspathfragment",
1116			],
1117			updatable: false,
1118		}
1119
1120		apex_key {
1121			name: "myapex.key",
1122			public_key: "testkey.avbpubkey",
1123			private_key: "testkey.pem",
1124		}
1125
1126		java_sdk_library {
1127			name: "foo",
1128			srcs: ["b.java"],
1129			shared_library: false,
1130			public: {enabled: true},
1131			apex_available: [
1132				"myapex",
1133			],
1134		}
1135
1136		java_library {
1137			name: "bar",
1138			srcs: ["b.java"],
1139			installable: true,
1140			apex_available: [
1141				"myapex",
1142			],
1143		}
1144
1145		bootclasspath_fragment {
1146			name: "mybootclasspathfragment",
1147			contents: [
1148				"foo",
1149				"bar",
1150			],
1151			apex_available: [
1152				"myapex",
1153			],
1154			additional_stubs: ["android-non-updatable"],
1155			fragments: [
1156				{
1157					apex: "com.android.art",
1158					module: "art-bootclasspath-fragment",
1159				},
1160			],
1161		}
1162	`)
1163
1164	java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{
1165		"art-bootclasspath-fragment",
1166		"bar",
1167		"dex2oatd",
1168		"foo",
1169		"prebuilt_sdk_module-lib_current_android-non-updatable",
1170		"prebuilt_sdk_public_current_android-non-updatable",
1171		"prebuilt_sdk_system_current_android-non-updatable",
1172		"prebuilt_sdk_test_current_android-non-updatable",
1173	})
1174
1175	nonUpdatablePublicStubs := getDexJarPath(result, "sdk_public_current_android-non-updatable")
1176	nonUpdatableSystemStubs := getDexJarPath(result, "sdk_system_current_android-non-updatable")
1177	nonUpdatableTestStubs := getDexJarPath(result, "sdk_test_current_android-non-updatable")
1178	nonUpdatableModuleLibStubs := getDexJarPath(result, "sdk_module-lib_current_android-non-updatable")
1179
1180	// Make sure that the fragment uses the android-non-updatable modules when generating the hidden
1181	// API flags.
1182	fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
1183
1184	rule := fragment.Rule("modularHiddenAPIStubFlagsFile")
1185	command := rule.RuleParams.Command
1186	android.AssertStringDoesContain(t, "check correct rule", command, "hiddenapi list")
1187
1188	// Make sure that the module_lib non-updatable stubs are available for resolving references from
1189	// the implementation boot dex jars provided by this module.
1190	android.AssertStringDoesContain(t, "android-non-updatable widest", command, "--dependency-stub-dex="+nonUpdatableModuleLibStubs)
1191
1192	// Make sure that the appropriate non-updatable stubs are available for resolving references from
1193	// the different API stubs provided by this module.
1194	android.AssertStringDoesContain(t, "public", command, "--public-stub-classpath="+nonUpdatablePublicStubs)
1195	android.AssertStringDoesContain(t, "system", command, "--system-stub-classpath="+nonUpdatableSystemStubs)
1196	android.AssertStringDoesContain(t, "test", command, "--test-stub-classpath="+nonUpdatableTestStubs)
1197}
1198
1199// TODO(b/177892522) - add test for host apex.
1200