• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2021 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package apex
16
17import (
18	"fmt"
19	"strings"
20	"testing"
21
22	"android/soong/android"
23	"android/soong/java"
24	"github.com/google/blueprint"
25	"github.com/google/blueprint/proptools"
26)
27
28// Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
29// apexes.
30
31var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers(
32	java.PrepareForTestWithDexpreopt,
33	PrepareForTestWithApexBuildComponents,
34)
35
36func TestPlatformBootclasspath_Fragments(t *testing.T) {
37	result := android.GroupFixturePreparers(
38		prepareForTestWithPlatformBootclasspath,
39		prepareForTestWithMyapex,
40		java.PrepareForTestWithJavaSdkLibraryFiles,
41		java.FixtureWithLastReleaseApis("foo"),
42		java.FixtureConfigureBootJars("myapex:bar"),
43		android.FixtureWithRootAndroidBp(`
44			platform_bootclasspath {
45				name: "platform-bootclasspath",
46				fragments: [
47					{
48						apex: "myapex",
49						module:"bar-fragment",
50					},
51				],
52				hidden_api: {
53					unsupported: [
54							"unsupported.txt",
55					],
56					removed: [
57							"removed.txt",
58					],
59					max_target_r_low_priority: [
60							"max-target-r-low-priority.txt",
61					],
62					max_target_q: [
63							"max-target-q.txt",
64					],
65					max_target_p: [
66							"max-target-p.txt",
67					],
68					max_target_o_low_priority: [
69							"max-target-o-low-priority.txt",
70					],
71					blocked: [
72							"blocked.txt",
73					],
74					unsupported_packages: [
75							"unsupported-packages.txt",
76					],
77				},
78			}
79
80			apex {
81				name: "myapex",
82				key: "myapex.key",
83				bootclasspath_fragments: [
84					"bar-fragment",
85				],
86				updatable: false,
87			}
88
89			apex_key {
90				name: "myapex.key",
91				public_key: "testkey.avbpubkey",
92				private_key: "testkey.pem",
93			}
94
95			bootclasspath_fragment {
96				name: "bar-fragment",
97				contents: ["bar"],
98				apex_available: ["myapex"],
99				api: {
100					stub_libs: ["foo"],
101				},
102				hidden_api: {
103					unsupported: [
104							"bar-unsupported.txt",
105					],
106					removed: [
107							"bar-removed.txt",
108					],
109					max_target_r_low_priority: [
110							"bar-max-target-r-low-priority.txt",
111					],
112					max_target_q: [
113							"bar-max-target-q.txt",
114					],
115					max_target_p: [
116							"bar-max-target-p.txt",
117					],
118					max_target_o_low_priority: [
119							"bar-max-target-o-low-priority.txt",
120					],
121					blocked: [
122							"bar-blocked.txt",
123					],
124					unsupported_packages: [
125							"bar-unsupported-packages.txt",
126					],
127				},
128			}
129
130			java_library {
131				name: "bar",
132				apex_available: ["myapex"],
133				srcs: ["a.java"],
134				system_modules: "none",
135				sdk_version: "none",
136				compile_dex: true,
137				permitted_packages: ["bar"],
138			}
139
140			java_sdk_library {
141				name: "foo",
142				srcs: ["a.java"],
143				public: {
144					enabled: true,
145				},
146				compile_dex: true,
147			}
148		`),
149	).RunTest(t)
150
151	pbcp := result.Module("platform-bootclasspath", "android_common")
152	info := result.ModuleProvider(pbcp, java.MonolithicHiddenAPIInfoProvider).(java.MonolithicHiddenAPIInfo)
153
154	for _, category := range java.HiddenAPIFlagFileCategories {
155		name := category.PropertyName
156		message := fmt.Sprintf("category %s", name)
157		filename := strings.ReplaceAll(name, "_", "-")
158		expected := []string{fmt.Sprintf("%s.txt", filename), fmt.Sprintf("bar-%s.txt", filename)}
159		android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category])
160	}
161
162	android.AssertPathsRelativeToTopEquals(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/stub-flags.csv"}, info.StubFlagsPaths)
163	android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths)
164	android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/metadata.csv"}, info.MetadataPaths)
165	android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/index.csv"}, info.IndexPaths)
166	android.AssertPathsRelativeToTopEquals(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex10000/modular-hiddenapi/all-flags.csv"}, info.AllFlagsPaths)
167}
168
169func TestPlatformBootclasspathDependencies(t *testing.T) {
170	result := android.GroupFixturePreparers(
171		prepareForTestWithPlatformBootclasspath,
172		prepareForTestWithArtApex,
173		prepareForTestWithMyapex,
174		// Configure some libraries in the art and framework boot images.
175		java.FixtureConfigureBootJars("com.android.art:baz", "com.android.art:quuz", "platform:foo"),
176		java.FixtureConfigureUpdatableBootJars("myapex:bar"),
177		java.PrepareForTestWithJavaSdkLibraryFiles,
178		java.FixtureWithLastReleaseApis("foo"),
179	).RunTestWithBp(t, `
180		apex {
181			name: "com.android.art",
182			key: "com.android.art.key",
183 			bootclasspath_fragments: [
184				"art-bootclasspath-fragment",
185			],
186			updatable: false,
187		}
188
189		apex_key {
190			name: "com.android.art.key",
191			public_key: "com.android.art.avbpubkey",
192			private_key: "com.android.art.pem",
193		}
194
195		bootclasspath_fragment {
196			name: "art-bootclasspath-fragment",
197			apex_available: [
198				"com.android.art",
199			],
200			contents: [
201				"baz",
202				"quuz",
203			],
204		}
205
206		java_library {
207			name: "baz",
208			apex_available: [
209				"com.android.art",
210			],
211			srcs: ["b.java"],
212			installable: true,
213		}
214
215		// Add a java_import that is not preferred and so won't have an appropriate apex variant created
216		// for it to make sure that the platform_bootclasspath doesn't try and add a dependency onto it.
217		java_import {
218			name: "baz",
219			apex_available: [
220				"com.android.art",
221			],
222			jars: ["b.jar"],
223		}
224
225		java_library {
226			name: "quuz",
227			apex_available: [
228				"com.android.art",
229			],
230			srcs: ["b.java"],
231			installable: true,
232		}
233
234		apex {
235			name: "myapex",
236			key: "myapex.key",
237			bootclasspath_fragments: [
238				"my-bootclasspath-fragment",
239			],
240			updatable: false,
241		}
242
243		bootclasspath_fragment {
244			name: "my-bootclasspath-fragment",
245			contents: ["bar"],
246			apex_available: ["myapex"],
247		}
248
249		apex_key {
250			name: "myapex.key",
251			public_key: "testkey.avbpubkey",
252			private_key: "testkey.pem",
253		}
254
255		java_sdk_library {
256			name: "foo",
257			srcs: ["b.java"],
258		}
259
260		java_library {
261			name: "bar",
262			srcs: ["b.java"],
263			installable: true,
264			apex_available: ["myapex"],
265			permitted_packages: ["bar"],
266		}
267
268		platform_bootclasspath {
269			name: "myplatform-bootclasspath",
270
271			fragments: [
272				{
273					apex: "com.android.art",
274					module: "art-bootclasspath-fragment",
275				},
276				{
277					apex: "myapex",
278					module: "my-bootclasspath-fragment",
279				},
280			],
281		}
282`,
283	)
284
285	java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
286		// The configured contents of BootJars.
287		"com.android.art:baz",
288		"com.android.art:quuz",
289		"platform:foo",
290
291		// The configured contents of UpdatableBootJars.
292		"myapex:bar",
293	})
294
295	java.CheckPlatformBootclasspathFragments(t, result, "myplatform-bootclasspath", []string{
296		"com.android.art:art-bootclasspath-fragment",
297		"myapex:my-bootclasspath-fragment",
298	})
299
300	// Make sure that the myplatform-bootclasspath has the correct dependencies.
301	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
302		// The following are stubs.
303		`platform:android_stubs_current`,
304		`platform:android_system_stubs_current`,
305		`platform:android_test_stubs_current`,
306		`platform:legacy.core.platform.api.stubs`,
307
308		// Needed for generating the boot image.
309		`platform:dex2oatd`,
310
311		// The configured contents of BootJars.
312		`com.android.art:baz`,
313		`com.android.art:quuz`,
314		`platform:foo`,
315
316		// The configured contents of UpdatableBootJars.
317		`myapex:bar`,
318
319		// The fragments.
320		`com.android.art:art-bootclasspath-fragment`,
321		`myapex:my-bootclasspath-fragment`,
322	})
323}
324
325// TestPlatformBootclasspath_AlwaysUsePrebuiltSdks verifies that the build does not fail when
326// AlwaysUsePrebuiltSdk() returns true. The structure of the modules in this test matches what
327// currently exists in some places in the Android build but it is not the intended structure. It is
328// in fact an invalid structure that should cause build failures. However, fixing that structure
329// will take too long so in the meantime this tests the workarounds to avoid build breakages.
330//
331// The main issues with this structure are:
332// 1. There is no prebuilt_bootclasspath_fragment referencing the "foo" java_sdk_library_import.
333// 2. There is no prebuilt_apex/apex_set which makes the dex implementation jar available to the
334//    prebuilt_bootclasspath_fragment and the "foo" java_sdk_library_import.
335//
336// Together these cause the following symptoms:
337// 1. The "foo" java_sdk_library_import does not have a dex implementation jar.
338// 2. The "foo" java_sdk_library_import does not have a myapex variant.
339//
340// TODO(b/179354495): Fix the structure in this test once the main Android build has been fixed.
341func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
342	result := android.GroupFixturePreparers(
343		prepareForTestWithPlatformBootclasspath,
344		prepareForTestWithMyapex,
345		// Configure two libraries, the first is a java_sdk_library whose prebuilt will be used because
346		// of AlwaysUsePrebuiltsSdk() but does not have an appropriate apex variant and does not provide
347		// a boot dex jar. The second is a normal library that is unaffected. The order matters because
348		// if the dependency on myapex:foo is filtered out because of either of those conditions then
349		// the dependencies resolved by the platform_bootclasspath will not match the configured list
350		// and so will fail the test.
351		java.FixtureConfigureUpdatableBootJars("myapex:foo", "myapex:bar"),
352		java.PrepareForTestWithJavaSdkLibraryFiles,
353		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
354			variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
355		}),
356		java.FixtureWithPrebuiltApis(map[string][]string{
357			"current": {},
358			"30":      {"foo"},
359		}),
360	).RunTestWithBp(t, `
361		apex {
362			name: "myapex",
363			key: "myapex.key",
364			bootclasspath_fragments: [
365				"mybootclasspath-fragment",
366			],
367			updatable: false,
368		}
369
370		apex_key {
371			name: "myapex.key",
372			public_key: "testkey.avbpubkey",
373			private_key: "testkey.pem",
374		}
375
376		java_library {
377			name: "bar",
378			srcs: ["b.java"],
379			installable: true,
380			apex_available: ["myapex"],
381			permitted_packages: ["bar"],
382		}
383
384		java_sdk_library {
385			name: "foo",
386			srcs: ["b.java"],
387			shared_library: false,
388			public: {
389				enabled: true,
390			},
391			apex_available: ["myapex"],
392			permitted_packages: ["foo"],
393		}
394
395		// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
396		// because AlwaysUsePrebuiltSdks() is true.
397		java_sdk_library_import {
398			name: "foo",
399			prefer: false,
400			shared_library: false,
401			permitted_packages: ["foo"],
402			public: {
403				jars: ["sdk_library/public/foo-stubs.jar"],
404				stub_srcs: ["sdk_library/public/foo_stub_sources"],
405				current_api: "sdk_library/public/foo.txt",
406				removed_api: "sdk_library/public/foo-removed.txt",
407				sdk_version: "current",
408			},
409			apex_available: ["myapex"],
410		}
411
412		// This always depends on the source foo module, its dependencies are not affected by the
413		// AlwaysUsePrebuiltSdks().
414		bootclasspath_fragment {
415			name: "mybootclasspath-fragment",
416			apex_available: [
417				"myapex",
418			],
419			contents: [
420				"foo", "bar",
421			],
422		}
423
424		platform_bootclasspath {
425			name: "myplatform-bootclasspath",
426			fragments: [
427				{
428					apex: "myapex",
429					module:"mybootclasspath-fragment",
430				},
431			],
432		}
433`,
434	)
435
436	java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
437		// The configured contents of BootJars.
438		"platform:prebuilt_foo", // Note: This is the platform not myapex variant.
439		"myapex:bar",
440	})
441
442	// Make sure that the myplatform-bootclasspath has the correct dependencies.
443	CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
444		// The following are stubs.
445		"platform:prebuilt_sdk_public_current_android",
446		"platform:prebuilt_sdk_system_current_android",
447		"platform:prebuilt_sdk_test_current_android",
448
449		// Not a prebuilt as no prebuilt existed when it was added.
450		"platform:legacy.core.platform.api.stubs",
451
452		// Needed for generating the boot image.
453		"platform:dex2oatd",
454
455		// The platform_bootclasspath intentionally adds dependencies on both source and prebuilt
456		// modules when available as it does not know which one will be preferred.
457		//
458		// The source module has an APEX variant but the prebuilt does not.
459		"myapex:foo",
460		"platform:prebuilt_foo",
461
462		// Only a source module exists.
463		"myapex:bar",
464
465		// The fragments.
466		"myapex:mybootclasspath-fragment",
467	})
468}
469
470// CheckModuleDependencies checks the dependencies of the selected module against the expected list.
471//
472// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
473// name of the apex, or platform is it is not part of an apex and <module> is the module name.
474func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
475	t.Helper()
476	module := ctx.ModuleForTests(name, variant).Module()
477	modules := []android.Module{}
478	ctx.VisitDirectDeps(module, func(m blueprint.Module) {
479		modules = append(modules, m.(android.Module))
480	})
481
482	pairs := java.ApexNamePairsFromModules(ctx, modules)
483	android.AssertDeepEquals(t, "module dependencies", expected, pairs)
484}
485