• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2021 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
18	"fmt"
19
20	"android/soong/android"
21	"android/soong/dexpreopt"
22)
23
24func init() {
25	registerPlatformBootclasspathBuildComponents(android.InitRegistrationContext)
26}
27
28func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
29	ctx.RegisterSingletonModuleType("platform_bootclasspath", platformBootclasspathFactory)
30}
31
32// The tags used for the dependencies between the platform bootclasspath and any configured boot
33// jars.
34var (
35	platformBootclasspathArtBootJarDepTag  = bootclasspathDependencyTag{name: "art-boot-jar"}
36	platformBootclasspathBootJarDepTag     = bootclasspathDependencyTag{name: "platform-boot-jar"}
37	platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"}
38)
39
40type platformBootclasspathModule struct {
41	android.SingletonModuleBase
42	ClasspathFragmentBase
43
44	properties platformBootclasspathProperties
45
46	// The apex:module pairs obtained from the configured modules.
47	configuredModules []android.Module
48
49	// The apex:module pairs obtained from the fragments.
50	fragments []android.Module
51
52	// Path to the monolithic hiddenapi-flags.csv file.
53	hiddenAPIFlagsCSV android.OutputPath
54
55	// Path to the monolithic hiddenapi-index.csv file.
56	hiddenAPIIndexCSV android.OutputPath
57
58	// Path to the monolithic hiddenapi-unsupported.csv file.
59	hiddenAPIMetadataCSV android.OutputPath
60}
61
62type platformBootclasspathProperties struct {
63	BootclasspathFragmentsDepsProperties
64
65	HiddenAPIFlagFileProperties
66}
67
68func platformBootclasspathFactory() android.SingletonModule {
69	m := &platformBootclasspathModule{}
70	m.AddProperties(&m.properties)
71	initClasspathFragment(m, BOOTCLASSPATH)
72	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
73	return m
74}
75
76var _ android.OutputFileProducer = (*platformBootclasspathModule)(nil)
77
78func (b *platformBootclasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) {
79	entries = append(entries, android.AndroidMkEntries{
80		Class: "FAKE",
81		// Need at least one output file in order for this to take effect.
82		OutputFile: android.OptionalPathForPath(b.hiddenAPIFlagsCSV),
83		Include:    "$(BUILD_PHONY_PACKAGE)",
84	})
85	entries = append(entries, b.classpathFragmentBase().androidMkEntries()...)
86	return
87}
88
89// Make the hidden API files available from the platform-bootclasspath module.
90func (b *platformBootclasspathModule) OutputFiles(tag string) (android.Paths, error) {
91	switch tag {
92	case "hiddenapi-flags.csv":
93		return android.Paths{b.hiddenAPIFlagsCSV}, nil
94	case "hiddenapi-index.csv":
95		return android.Paths{b.hiddenAPIIndexCSV}, nil
96	case "hiddenapi-metadata.csv":
97		return android.Paths{b.hiddenAPIMetadataCSV}, nil
98	}
99
100	return nil, fmt.Errorf("unknown tag %s", tag)
101}
102
103func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) {
104	b.hiddenAPIDepsMutator(ctx)
105
106	if !dexpreopt.IsDex2oatNeeded(ctx) {
107		return
108	}
109
110	// Add a dependency onto the dex2oat tool which is needed for creating the boot image. The
111	// path is retrieved from the dependency by GetGlobalSoongConfig(ctx).
112	dexpreopt.RegisterToolDeps(ctx)
113}
114
115func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) {
116	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
117		return
118	}
119
120	// Add dependencies onto the stub lib modules.
121	apiLevelToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config())
122	hiddenAPIAddStubLibDependencies(ctx, apiLevelToStubLibModules)
123}
124
125func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
126	// Add dependencies on all the modules configured in the "art" boot image.
127	artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
128	addDependenciesOntoBootImageModules(ctx, artImageConfig.modules, platformBootclasspathArtBootJarDepTag)
129
130	// Add dependencies on all the non-updatable module configured in the "boot" boot image. That does
131	// not include modules configured in the "art" boot image.
132	addDependenciesOntoBootImageModules(ctx, b.platformJars(ctx), platformBootclasspathBootJarDepTag)
133
134	// Add dependencies on all the apex jars.
135	apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
136	addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag)
137
138	// Add dependencies on all the fragments.
139	b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
140}
141
142func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) {
143	for i := 0; i < modules.Len(); i++ {
144		apex := modules.Apex(i)
145		name := modules.Jar(i)
146
147		addDependencyOntoApexModulePair(ctx, apex, name, tag)
148	}
149}
150
151// GenerateSingletonBuildActions does nothing and must never do anything.
152//
153// This module only implements android.SingletonModule so that it can implement
154// android.SingletonMakeVarsProvider.
155func (b *platformBootclasspathModule) GenerateSingletonBuildActions(android.SingletonContext) {
156	// Keep empty
157}
158
159func (d *platformBootclasspathModule) MakeVars(ctx android.MakeVarsContext) {
160	d.generateHiddenApiMakeVars(ctx)
161}
162
163func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
164	// Gather all the dependencies from the art, platform, and apex boot jars.
165	artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag)
166	platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathBootJarDepTag)
167	apexModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathApexBootJarDepTag)
168
169	// Concatenate them all, in order as they would appear on the bootclasspath.
170	var allModules []android.Module
171	allModules = append(allModules, artModules...)
172	allModules = append(allModules, platformModules...)
173	allModules = append(allModules, apexModules...)
174	b.configuredModules = allModules
175
176	// Gather all the fragments dependencies.
177	b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
178
179	// Check the configuration of the boot modules.
180	// ART modules are checked by the art-bootclasspath-fragment.
181	b.checkPlatformModules(ctx, platformModules)
182	b.checkApexModules(ctx, apexModules)
183
184	b.generateClasspathProtoBuildActions(ctx)
185
186	bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments)
187	buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule)
188
189	b.generateBootImageBuildActions(ctx)
190	b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules)
191}
192
193// Generate classpaths.proto config
194func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
195	configuredJars := b.configuredJars(ctx)
196	// ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
197	classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
198	b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
199}
200
201func (b *platformBootclasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList {
202	// Include all non APEX jars
203	jars := b.platformJars(ctx)
204
205	// Include jars from APEXes that don't populate their classpath proto config.
206	remainingJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
207	for _, fragment := range b.fragments {
208		info := ctx.OtherModuleProvider(fragment, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo)
209		if info.ClasspathFragmentProtoGenerated {
210			remainingJars = remainingJars.RemoveList(info.ClasspathFragmentProtoContents)
211		}
212	}
213	for i := 0; i < remainingJars.Len(); i++ {
214		jars = jars.Append(remainingJars.Apex(i), remainingJars.Jar(i))
215	}
216
217	return jars
218}
219
220func (b *platformBootclasspathModule) platformJars(ctx android.PathContext) android.ConfiguredJarList {
221	return defaultBootImageConfig(ctx).modules.RemoveList(artBootImageConfig(ctx).modules)
222}
223
224// checkPlatformModules ensures that the non-updatable modules supplied are not part of an
225// apex module.
226func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) {
227	// TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here.
228	for _, m := range modules {
229		apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
230		fromUpdatableApex := apexInfo.Updatable
231		if fromUpdatableApex {
232			// error: this jar is part of an updatable apex
233			ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the platform bootclasspath", ctx.OtherModuleName(m), apexInfo.InApexVariants)
234		} else {
235			// ok: this jar is part of the platform or a non-updatable apex
236		}
237	}
238}
239
240// checkApexModules ensures that the apex modules supplied are not from the platform.
241func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) {
242	for _, m := range modules {
243		apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
244		fromUpdatableApex := apexInfo.Updatable
245		if fromUpdatableApex {
246			// ok: this jar is part of an updatable apex
247		} else {
248			name := ctx.OtherModuleName(m)
249			if apexInfo.IsForPlatform() {
250				// If AlwaysUsePrebuiltSdks() returns true then it is possible that the updatable list will
251				// include platform variants of a prebuilt module due to workarounds elsewhere. In that case
252				// do not treat this as an error.
253				// TODO(b/179354495): Always treat this as an error when migration to bootclasspath_fragment
254				//  modules is complete.
255				if !ctx.Config().AlwaysUsePrebuiltSdks() {
256					// error: this jar is part of the platform
257					ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name)
258				}
259			} else {
260				// TODO(b/177892522): Treat this as an error.
261				// Cannot do that at the moment because framework-wifi and framework-tethering are in the
262				// PRODUCT_APEX_BOOT_JARS but not marked as updatable in AOSP.
263			}
264		}
265	}
266}
267
268// generateHiddenAPIBuildActions generates all the hidden API related build rules.
269func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) bootDexJarByModule {
270
271	// Save the paths to the monolithic files for retrieval via OutputFiles().
272	b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags
273	b.hiddenAPIIndexCSV = hiddenAPISingletonPaths(ctx).index
274	b.hiddenAPIMetadataCSV = hiddenAPISingletonPaths(ctx).metadata
275
276	bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules)
277
278	// Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance
279	// optimization that can be used to reduce the incremental build time but as its name suggests it
280	// can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath.
281	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
282		paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
283		for _, path := range paths {
284			ctx.Build(pctx, android.BuildParams{
285				Rule:   android.Touch,
286				Output: path,
287			})
288		}
289		return bootDexJarByModule
290	}
291
292	// Construct a list of ClasspathElement objects from the modules and fragments.
293	classpathElements := CreateClasspathElements(ctx, modules, fragments)
294
295	monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, classpathElements)
296
297	// Extract the classes jars only from those libraries that do not have corresponding fragments as
298	// the fragments will have already provided the flags that are needed.
299	classesJars := monolithicInfo.ClassesJars
300
301	// Create the input to pass to buildRuleToGenerateHiddenAPIStubFlagsFile
302	input := newHiddenAPIFlagInput()
303
304	// Gather stub library information from the dependencies on modules provided by
305	// hiddenAPIComputeMonolithicStubLibModules.
306	input.gatherStubLibInfo(ctx, nil)
307
308	// Use the flag files from this module and all the fragments.
309	input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory
310
311	// Generate the monolithic stub-flags.csv file.
312	stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
313	buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagSubsets)
314
315	// Generate the annotation-flags.csv file from all the module annotations.
316	annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags-from-classes.csv")
317	buildRuleToGenerateAnnotationFlags(ctx, "intermediate hidden API flags", classesJars, stubFlags, annotationFlags)
318
319	// Generate the monolithic hiddenapi-flags.csv file.
320	//
321	// Use annotation flags generated directly from the classes jars as well as annotation flag files
322	// provided by prebuilts.
323	allAnnotationFlagFiles := android.Paths{annotationFlags}
324	allAnnotationFlagFiles = append(allAnnotationFlagFiles, monolithicInfo.AnnotationFlagsPaths...)
325	allFlags := hiddenAPISingletonPaths(ctx).flags
326	buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.FlagSubsets, android.OptionalPath{})
327
328	// Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations
329	// in the source code.
330	intermediateMetadataCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "metadata-from-classes.csv")
331	buildRuleToGenerateMetadata(ctx, "intermediate hidden API metadata", classesJars, stubFlags, intermediateMetadataCSV)
332
333	// Generate the monolithic hiddenapi-metadata.csv file.
334	//
335	// Use metadata files generated directly from the classes jars as well as metadata files provided
336	// by prebuilts.
337	//
338	// This has the side effect of ensuring that the output file uses | quotes just in case that is
339	// important for the tools that consume the metadata file.
340	allMetadataFlagFiles := android.Paths{intermediateMetadataCSV}
341	allMetadataFlagFiles = append(allMetadataFlagFiles, monolithicInfo.MetadataPaths...)
342	metadataCSV := hiddenAPISingletonPaths(ctx).metadata
343	b.buildRuleMergeCSV(ctx, "monolithic hidden API metadata", allMetadataFlagFiles, metadataCSV)
344
345	// Generate an intermediate monolithic hiddenapi-index.csv file directly from the CSV files in the
346	// classes jars.
347	intermediateIndexCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "index-from-classes.csv")
348	buildRuleToGenerateIndex(ctx, "intermediate hidden API index", classesJars, intermediateIndexCSV)
349
350	// Generate the monolithic hiddenapi-index.csv file.
351	//
352	// Use index files generated directly from the classes jars as well as index files provided
353	// by prebuilts.
354	allIndexFlagFiles := android.Paths{intermediateIndexCSV}
355	allIndexFlagFiles = append(allIndexFlagFiles, monolithicInfo.IndexPaths...)
356	indexCSV := hiddenAPISingletonPaths(ctx).index
357	b.buildRuleMergeCSV(ctx, "monolithic hidden API index", allIndexFlagFiles, indexCSV)
358
359	return bootDexJarByModule
360}
361
362// createAndProvideMonolithicHiddenAPIInfo creates a MonolithicHiddenAPIInfo and provides it for
363// testing.
364func (b *platformBootclasspathModule) createAndProvideMonolithicHiddenAPIInfo(ctx android.ModuleContext, classpathElements ClasspathElements) MonolithicHiddenAPIInfo {
365	// Create a temporary input structure in which to collate information provided directly by this
366	// module, either through properties or direct dependencies.
367	temporaryInput := newHiddenAPIFlagInput()
368
369	// Create paths to the flag files specified in the properties.
370	temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.HiddenAPIFlagFileProperties)
371
372	// Create the monolithic info, by starting with the flag files specified on this and then merging
373	// in information from all the fragment dependencies of this.
374	monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, classpathElements)
375
376	// Store the information for testing.
377	ctx.SetProvider(MonolithicHiddenAPIInfoProvider, monolithicInfo)
378	return monolithicInfo
379}
380
381func (b *platformBootclasspathModule) buildRuleMergeCSV(ctx android.ModuleContext, desc string, inputPaths android.Paths, outputPath android.WritablePath) {
382	rule := android.NewRuleBuilder(pctx, ctx)
383	rule.Command().
384		BuiltTool("merge_csv").
385		Flag("--key_field signature").
386		FlagWithOutput("--output=", outputPath).
387		Inputs(inputPaths)
388
389	rule.Build(desc, desc)
390}
391
392// generateHiddenApiMakeVars generates make variables needed by hidden API related make rules, e.g.
393// veridex and run-appcompat.
394func (b *platformBootclasspathModule) generateHiddenApiMakeVars(ctx android.MakeVarsContext) {
395	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
396		return
397	}
398	// INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
399	ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String())
400}
401
402// generateBootImageBuildActions generates ninja rules related to the boot image creation.
403func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext) {
404	// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
405	// GenerateSingletonBuildActions method as it cannot create it for itself.
406	dexpreopt.GetGlobalSoongConfig(ctx)
407
408	global := dexpreopt.GetGlobalConfig(ctx)
409	if !shouldBuildBootImages(ctx.Config(), global) {
410		return
411	}
412
413	frameworkBootImageConfig := defaultBootImageConfig(ctx)
414	bootFrameworkProfileRule(ctx, frameworkBootImageConfig)
415	b.generateBootImage(ctx, frameworkBootImageName)
416	b.generateBootImage(ctx, mainlineBootImageName)
417	dumpOatRules(ctx, frameworkBootImageConfig)
418}
419
420func (b *platformBootclasspathModule) generateBootImage(ctx android.ModuleContext, imageName string) {
421	imageConfig := genBootImageConfigs(ctx)[imageName]
422
423	modules := b.getModulesForImage(ctx, imageConfig)
424
425	// Copy module dex jars to their predefined locations.
426	bootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, modules)
427	copyBootJarsToPredefinedLocations(ctx, bootDexJarsByModule, imageConfig.dexPathsByModule)
428
429	// Build a profile for the image config and then use that to build the boot image.
430	profile := bootImageProfileRule(ctx, imageConfig)
431
432	// If dexpreopt of boot image jars should be skipped, generate only a profile.
433	global := dexpreopt.GetGlobalConfig(ctx)
434	if global.DisablePreoptBootImages {
435		return
436	}
437
438	// Build boot image files for the android variants.
439	androidBootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
440
441	// Zip the android variant boot image files up.
442	buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFiles.byArch)
443
444	// Build boot image files for the host variants. There are use directly by ART host side tests.
445	buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
446}
447
448// Copy apex module dex jars to their predefined locations. They will be used for dexpreopt for apps.
449func (b *platformBootclasspathModule) copyApexBootJarsForAppsDexpreopt(ctx android.ModuleContext, apexModules []android.Module) {
450	config := GetApexBootConfig(ctx)
451	apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules)
452	copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule)
453}
454
455func (b *platformBootclasspathModule) getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []android.Module {
456	modules := make([]android.Module, 0, imageConfig.modules.Len())
457	for i := 0; i < imageConfig.modules.Len(); i++ {
458		found := false
459		for _, module := range b.configuredModules {
460			name := android.RemoveOptionalPrebuiltPrefix(module.Name())
461			if name == imageConfig.modules.Jar(i) {
462				modules = append(modules, module)
463				found = true
464				break
465			}
466		}
467		if !found && !ctx.Config().AllowMissingDependencies() {
468			ctx.ModuleErrorf(
469				"Boot image '%s' module '%s' not added as a dependency of platform_bootclasspath",
470				imageConfig.name,
471				imageConfig.modules.Jar(i))
472			return []android.Module{}
473		}
474	}
475	return modules
476}
477