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 java
16
17import (
18	"fmt"
19	"path/filepath"
20	"reflect"
21	"strings"
22
23	"android/soong/android"
24	"android/soong/dexpreopt"
25
26	"github.com/google/blueprint/proptools"
27
28	"github.com/google/blueprint"
29)
30
31func init() {
32	registerBootclasspathFragmentBuildComponents(android.InitRegistrationContext)
33
34	android.RegisterSdkMemberType(&bootclasspathFragmentMemberType{
35		SdkMemberTypeBase: android.SdkMemberTypeBase{
36			PropertyName: "bootclasspath_fragments",
37			SupportsSdk:  true,
38		},
39	})
40}
41
42func registerBootclasspathFragmentBuildComponents(ctx android.RegistrationContext) {
43	ctx.RegisterModuleType("bootclasspath_fragment", bootclasspathFragmentFactory)
44	ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootclasspathFragmentFactory)
45}
46
47type bootclasspathFragmentContentDependencyTag struct {
48	blueprint.BaseDependencyTag
49}
50
51// Avoid having to make bootclasspath_fragment content visible to the bootclasspath_fragment.
52//
53// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules
54// with proper dependencies.
55// TODO(b/177892522): Remove this and add needed visibility.
56func (b bootclasspathFragmentContentDependencyTag) ExcludeFromVisibilityEnforcement() {
57}
58
59// The bootclasspath_fragment contents must never depend on prebuilts.
60func (b bootclasspathFragmentContentDependencyTag) ReplaceSourceWithPrebuilt() bool {
61	return false
62}
63
64// SdkMemberType causes dependencies added with this tag to be automatically added to the sdk as if
65// they were specified using java_boot_libs or java_sdk_libs.
66func (b bootclasspathFragmentContentDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
67	// If the module is a java_sdk_library then treat it as if it was specified in the java_sdk_libs
68	// property, otherwise treat if it was specified in the java_boot_libs property.
69	if javaSdkLibrarySdkMemberType.IsInstance(child) {
70		return javaSdkLibrarySdkMemberType
71	}
72
73	return javaBootLibsSdkMemberType
74}
75
76func (b bootclasspathFragmentContentDependencyTag) ExportMember() bool {
77	return true
78}
79
80// Contents of bootclasspath fragments in an apex are considered to be directly in the apex, as if
81// they were listed in java_libs.
82func (b bootclasspathFragmentContentDependencyTag) CopyDirectlyInAnyApex() {}
83
84// Contents of bootclasspath fragments require files from prebuilt apex files.
85func (b bootclasspathFragmentContentDependencyTag) RequiresFilesFromPrebuiltApex() {}
86
87// The tag used for the dependency between the bootclasspath_fragment module and its contents.
88var bootclasspathFragmentContentDepTag = bootclasspathFragmentContentDependencyTag{}
89
90var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathFragmentContentDepTag
91var _ android.ReplaceSourceWithPrebuilt = bootclasspathFragmentContentDepTag
92var _ android.SdkMemberTypeDependencyTag = bootclasspathFragmentContentDepTag
93var _ android.CopyDirectlyInAnyApexTag = bootclasspathFragmentContentDepTag
94var _ android.RequiresFilesFromPrebuiltApexTag = bootclasspathFragmentContentDepTag
95
96func IsBootclasspathFragmentContentDepTag(tag blueprint.DependencyTag) bool {
97	return tag == bootclasspathFragmentContentDepTag
98}
99
100// Properties that can be different when coverage is enabled.
101type BootclasspathFragmentCoverageAffectedProperties struct {
102	// The contents of this bootclasspath_fragment, could be either java_library, or java_sdk_library.
103	//
104	// A java_sdk_library specified here will also be treated as if it was specified on the stub_libs
105	// property.
106	//
107	// The order of this list matters as it is the order that is used in the bootclasspath.
108	Contents []string
109
110	// The properties for specifying the API stubs provided by this fragment.
111	BootclasspathAPIProperties
112}
113
114type bootclasspathFragmentProperties struct {
115	// The name of the image this represents.
116	//
117	// If specified then it must be one of "art" or "boot".
118	Image_name *string
119
120	// Properties whose values need to differ with and without coverage.
121	BootclasspathFragmentCoverageAffectedProperties
122	Coverage BootclasspathFragmentCoverageAffectedProperties
123
124	// Hidden API related properties.
125	Hidden_api HiddenAPIFlagFileProperties
126
127	// The list of additional stub libraries which this fragment's contents use but which are not
128	// provided by another bootclasspath_fragment.
129	//
130	// Note, "android-non-updatable" is treated specially. While no such module exists it is treated
131	// as if it was a java_sdk_library. So, when public API stubs are needed then it will be replaced
132	// with "android-non-updatable.stubs", with "androidn-non-updatable.system.stubs" when the system
133	// stubs are needed and so on.
134	Additional_stubs []string
135
136	// Properties that allow a fragment to depend on other fragments. This is needed for hidden API
137	// processing as it needs access to all the classes used by a fragment including those provided
138	// by other fragments.
139	BootclasspathFragmentsDepsProperties
140}
141
142type BootclasspathFragmentModule struct {
143	android.ModuleBase
144	android.ApexModuleBase
145	android.SdkBase
146	ClasspathFragmentBase
147
148	properties bootclasspathFragmentProperties
149}
150
151// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt
152// bootclasspath fragment modules.
153type commonBootclasspathFragment interface {
154	// produceHiddenAPIOutput produces the all-flags.csv and intermediate files and encodes the flags
155	// into dex files.
156	//
157	// Returns a *HiddenAPIOutput containing the paths for the generated files. Returns nil if the
158	// module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a
159	// versioned sdk.
160	produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput
161
162	// produceBootImageFiles will attempt to produce rules to create the boot image files at the paths
163	// predefined in the bootImageConfig.
164	//
165	// If it could not create the files then it will return nil. Otherwise, it will return a map from
166	// android.ArchType to the predefined paths of the boot image files.
167	produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch
168}
169
170var _ commonBootclasspathFragment = (*BootclasspathFragmentModule)(nil)
171
172// bootImageFilesByArch is a map from android.ArchType to the paths to the boot image files.
173//
174// The paths include the .art, .oat and .vdex files, one for each of the modules from which the boot
175// image is created.
176type bootImageFilesByArch map[android.ArchType]android.Paths
177
178func bootclasspathFragmentFactory() android.Module {
179	m := &BootclasspathFragmentModule{}
180	m.AddProperties(&m.properties)
181	android.InitApexModule(m)
182	android.InitSdkAwareModule(m)
183	initClasspathFragment(m, BOOTCLASSPATH)
184	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
185
186	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
187		// If code coverage has been enabled for the framework then append the properties with
188		// coverage specific properties.
189		if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
190			err := proptools.AppendProperties(&m.properties.BootclasspathFragmentCoverageAffectedProperties, &m.properties.Coverage, nil)
191			if err != nil {
192				ctx.PropertyErrorf("coverage", "error trying to append coverage specific properties: %s", err)
193				return
194			}
195		}
196
197		// Initialize the contents property from the image_name.
198		bootclasspathFragmentInitContentsFromImage(ctx, m)
199	})
200	return m
201}
202
203// bootclasspathFragmentInitContentsFromImage will initialize the contents property from the image_name if
204// necessary.
205func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) {
206	contents := m.properties.Contents
207	if len(contents) == 0 {
208		ctx.PropertyErrorf("contents", "required property is missing")
209		return
210	}
211
212	if m.properties.Image_name == nil {
213		// Nothing to do.
214		return
215	}
216
217	imageName := proptools.String(m.properties.Image_name)
218	if imageName != "art" {
219		ctx.PropertyErrorf("image_name", `unknown image name %q, expected "art"`, imageName)
220		return
221	}
222
223	// TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
224	if android.IsModuleInVersionedSdk(m) {
225		// The module is a versioned prebuilt so ignore it. This is done for a couple of reasons:
226		// 1. There is no way to use this at the moment so ignoring it is safe.
227		// 2. Attempting to initialize the contents property from the configuration will end up having
228		//    the versioned prebuilt depending on the unversioned prebuilt. That will cause problems
229		//    as the unversioned prebuilt could end up with an APEX variant created for the source
230		//    APEX which will prevent it from having an APEX variant for the prebuilt APEX which in
231		//    turn will prevent it from accessing the dex implementation jar from that which will
232		//    break hidden API processing, amongst others.
233		return
234	}
235
236	// Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is
237	// too early in the Soong processing for that to work.
238	global := dexpreopt.GetGlobalConfig(ctx)
239	modules := global.ArtApexJars
240
241	// Make sure that the apex specified in the configuration is consistent and is one for which
242	// this boot image is available.
243	commonApex := ""
244	for i := 0; i < modules.Len(); i++ {
245		apex := modules.Apex(i)
246		jar := modules.Jar(i)
247		if apex == "platform" {
248			ctx.ModuleErrorf("ArtApexJars is invalid as it requests a platform variant of %q", jar)
249			continue
250		}
251		if !m.AvailableFor(apex) {
252			ctx.ModuleErrorf("ArtApexJars configuration incompatible with this module, ArtApexJars expects this to be in apex %q but this is only in apexes %q",
253				apex, m.ApexAvailable())
254			continue
255		}
256		if commonApex == "" {
257			commonApex = apex
258		} else if commonApex != apex {
259			ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q",
260				commonApex, apex)
261		}
262	}
263}
264
265// bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this
266// module (if any) matches the contents.
267//
268// This should be a noop as if image_name="art" then the contents will be set from the ArtApexJars
269// config by bootclasspathFragmentInitContentsFromImage so it will be guaranteed to match. However,
270// in future this will not be the case.
271func (b *BootclasspathFragmentModule) bootclasspathImageNameContentsConsistencyCheck(ctx android.BaseModuleContext) {
272	imageName := proptools.String(b.properties.Image_name)
273	if imageName == "art" {
274		// TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property.
275		if android.IsModuleInVersionedSdk(b) {
276			// The module is a versioned prebuilt so ignore it. This is done for a couple of reasons:
277			// 1. There is no way to use this at the moment so ignoring it is safe.
278			// 2. Attempting to initialize the contents property from the configuration will end up having
279			//    the versioned prebuilt depending on the unversioned prebuilt. That will cause problems
280			//    as the unversioned prebuilt could end up with an APEX variant created for the source
281			//    APEX which will prevent it from having an APEX variant for the prebuilt APEX which in
282			//    turn will prevent it from accessing the dex implementation jar from that which will
283			//    break hidden API processing, amongst others.
284			return
285		}
286
287		// Get the configuration for the art apex jars.
288		modules := b.getImageConfig(ctx).modules
289		configuredJars := modules.CopyOfJars()
290
291		// Skip the check if the configured jars list is empty as that is a common configuration when
292		// building targets that do not result in a system image.
293		if len(configuredJars) == 0 {
294			return
295		}
296
297		contents := b.properties.Contents
298		if !reflect.DeepEqual(configuredJars, contents) {
299			ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v",
300				configuredJars, contents)
301		}
302	}
303}
304
305var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(BootclasspathFragmentApexContentInfo{})
306
307// BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
308// apex contents.
309type BootclasspathFragmentApexContentInfo struct {
310	// The configured modules, will be empty if this is from a bootclasspath_fragment that does not
311	// set image_name: "art".
312	modules android.ConfiguredJarList
313
314	// Map from arch type to the boot image files.
315	bootImageFilesByArch bootImageFilesByArch
316
317	// Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the
318	// hidden API encoded dex jar path.
319	contentModuleDexJarPaths bootDexJarByModule
320}
321
322func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
323	return i.modules
324}
325
326// Get a map from ArchType to the associated boot image's contents for Android.
327//
328// Extension boot images only return their own files, not the files of the boot images they extend.
329func (i BootclasspathFragmentApexContentInfo) AndroidBootImageFilesByArchType() bootImageFilesByArch {
330	return i.bootImageFilesByArch
331}
332
333// DexBootJarPathForContentModule returns the path to the dex boot jar for specified module.
334//
335// The dex boot jar is one which has had hidden API encoding performed on it.
336func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) (android.Path, error) {
337	// A bootclasspath_fragment cannot use a prebuilt library so Name() will return the base name
338	// without a prebuilt_ prefix so is safe to use as the key for the contentModuleDexJarPaths.
339	name := module.Name()
340	if dexJar, ok := i.contentModuleDexJarPaths[name]; ok {
341		return dexJar, nil
342	} else {
343		return nil, fmt.Errorf("unknown bootclasspath_fragment content module %s, expected one of %s",
344			name, strings.Join(android.SortedStringKeys(i.contentModuleDexJarPaths), ", "))
345	}
346}
347
348func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
349	tag := ctx.OtherModuleDependencyTag(dep)
350	if IsBootclasspathFragmentContentDepTag(tag) {
351		// Boot image contents are automatically added to apex.
352		return true
353	}
354	if android.IsMetaDependencyTag(tag) {
355		// Cross-cutting metadata dependencies are metadata.
356		return false
357	}
358	panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag)))
359}
360
361func (b *BootclasspathFragmentModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
362	return nil
363}
364
365// ComponentDepsMutator adds dependencies onto modules before any prebuilt modules without a
366// corresponding source module are renamed. This means that adding a dependency using a name without
367// a prebuilt_ prefix will always resolve to a source module and when using a name with that prefix
368// it will always resolve to a prebuilt module.
369func (b *BootclasspathFragmentModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
370	module := ctx.Module()
371	_, isSourceModule := module.(*BootclasspathFragmentModule)
372
373	for _, name := range b.properties.Contents {
374		// A bootclasspath_fragment must depend only on other source modules, while the
375		// prebuilt_bootclasspath_fragment must only depend on other prebuilt modules.
376		//
377		// TODO(b/177892522) - avoid special handling of jacocoagent.
378		if !isSourceModule && name != "jacocoagent" {
379			name = android.PrebuiltNameFromSource(name)
380		}
381		ctx.AddDependency(module, bootclasspathFragmentContentDepTag, name)
382	}
383
384}
385
386func (b *BootclasspathFragmentModule) DepsMutator(ctx android.BottomUpMutatorContext) {
387	// Add dependencies onto all the modules that provide the API stubs for classes on this
388	// bootclasspath fragment.
389	hiddenAPIAddStubLibDependencies(ctx, b.properties.apiScopeToStubLibs())
390
391	for _, additionalStubModule := range b.properties.Additional_stubs {
392		for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
393			// Add a dependency onto a possibly scope specific stub library.
394			scopeSpecificDependency := apiScope.scopeSpecificStubModule(ctx, additionalStubModule)
395			tag := hiddenAPIStubsDependencyTag{apiScope: apiScope, fromAdditionalDependency: true}
396			ctx.AddVariationDependencies(nil, tag, scopeSpecificDependency)
397		}
398	}
399
400	if SkipDexpreoptBootJars(ctx) {
401		return
402	}
403
404	// Add a dependency onto the dex2oat tool which is needed for creating the boot image. The
405	// path is retrieved from the dependency by GetGlobalSoongConfig(ctx).
406	dexpreopt.RegisterToolDeps(ctx)
407}
408
409func (b *BootclasspathFragmentModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
410	// Add dependencies on all the fragments.
411	b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx)
412}
413
414func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
415	// Only perform a consistency check if this module is the active module. That will prevent an
416	// unused prebuilt that was created without instrumentation from breaking an instrumentation
417	// build.
418	if isActiveModule(ctx.Module()) {
419		b.bootclasspathImageNameContentsConsistencyCheck(ctx)
420	}
421
422	// Generate classpaths.proto config
423	b.generateClasspathProtoBuildActions(ctx)
424
425	// Gather the bootclasspath fragment's contents.
426	var contents []android.Module
427	ctx.VisitDirectDeps(func(module android.Module) {
428		tag := ctx.OtherModuleDependencyTag(module)
429		if IsBootclasspathFragmentContentDepTag(tag) {
430			contents = append(contents, module)
431		}
432	})
433
434	fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag)
435
436	// Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a
437	// prebuilt which will not use the image config.
438	imageConfig := b.getImageConfig(ctx)
439
440	// A versioned prebuilt_bootclasspath_fragment cannot and does not need to perform hidden API
441	// processing. It cannot do it because it is not part of a prebuilt_apex and so has no access to
442	// the correct dex implementation jar. It does not need to because the platform-bootclasspath
443	// always references the latest bootclasspath_fragments.
444	if !android.IsModuleInVersionedSdk(ctx.Module()) {
445		// Perform hidden API processing.
446		hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments)
447
448		var bootImageFilesByArch bootImageFilesByArch
449		if imageConfig != nil {
450			// Delegate the production of the boot image files to a module type specific method.
451			common := ctx.Module().(commonBootclasspathFragment)
452			bootImageFilesByArch = common.produceBootImageFiles(ctx, imageConfig)
453
454			if shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) {
455				// Zip the boot image files up, if available. This will generate the zip file in a
456				// predefined location.
457				buildBootImageZipInPredefinedLocation(ctx, imageConfig, bootImageFilesByArch)
458
459				// Copy the dex jars of this fragment's content modules to their predefined locations.
460				copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule)
461			}
462		}
463
464		// A prebuilt fragment cannot contribute to an apex.
465		if !android.IsModulePrebuilt(ctx.Module()) {
466			// Provide the apex content info.
467			b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFilesByArch)
468		}
469	}
470}
471
472// shouldCopyBootFilesToPredefinedLocations determines whether the current module should copy boot
473// files, e.g. boot dex jars or boot image files, to the predefined location expected by the rest
474// of the build.
475//
476// This ensures that only a single module will copy its files to the image configuration.
477func shouldCopyBootFilesToPredefinedLocations(ctx android.ModuleContext, imageConfig *bootImageConfig) bool {
478	// Bootclasspath fragment modules that are for the platform do not produce boot related files.
479	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
480	if apexInfo.IsForPlatform() {
481		return false
482	}
483
484	// If the image configuration has no modules specified then it means that the build has been
485	// configured to build something other than a boot image, e.g. an sdk, so do not try and copy the
486	// files.
487	if imageConfig.modules.Len() == 0 {
488		return false
489	}
490
491	// Only copy files from the module that is preferred.
492	return isActiveModule(ctx.Module())
493}
494
495// provideApexContentInfo creates, initializes and stores the apex content info for use by other
496// modules.
497func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, hiddenAPIOutput *HiddenAPIOutput, bootImageFilesByArch bootImageFilesByArch) {
498	// Construct the apex content info from the config.
499	info := BootclasspathFragmentApexContentInfo{
500		// Populate the apex content info with paths to the dex jars.
501		contentModuleDexJarPaths: hiddenAPIOutput.EncodedBootDexFilesByModule,
502	}
503
504	if imageConfig != nil {
505		info.modules = imageConfig.modules
506	}
507
508	info.bootImageFilesByArch = bootImageFilesByArch
509
510	// Make the apex content info available for other modules.
511	ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
512}
513
514// generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
515func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
516	var classpathJars []classpathJar
517	if "art" == proptools.String(b.properties.Image_name) {
518		// ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
519		classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
520	} else {
521		classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), b.classpathType)
522	}
523	b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
524}
525
526func (b *BootclasspathFragmentModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
527	if "art" == proptools.String(b.properties.Image_name) {
528		return b.getImageConfig(ctx).modules
529	}
530
531	global := dexpreopt.GetGlobalConfig(ctx)
532
533	possibleUpdatableModules := gatherPossibleUpdatableModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag)
534
535	// Only create configs for updatable boot jars. Non-updatable boot jars must be part of the
536	// platform_bootclasspath's classpath proto config to guarantee that they come before any
537	// updatable jars at runtime.
538	jars := global.UpdatableBootJars.Filter(possibleUpdatableModules)
539
540	// TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths
541	// config. However, any test specific jars would not be present in UpdatableBootJars. Instead,
542	// we should check if we are creating a config for apex_test via ApexInfo and amend the values.
543	// This is an exception to support end-to-end test for SdkExtensions, until such support exists.
544	if android.InList("test_framework-sdkextensions", possibleUpdatableModules) {
545		jars = jars.Append("com.android.sdkext", "test_framework-sdkextensions")
546	}
547	return jars
548}
549
550func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
551	// Get a map of the image configs that are supported.
552	imageConfigs := genBootImageConfigs(ctx)
553
554	// Retrieve the config for this image.
555	imageNamePtr := b.properties.Image_name
556	if imageNamePtr == nil {
557		return nil
558	}
559
560	imageName := *imageNamePtr
561	imageConfig := imageConfigs[imageName]
562	if imageConfig == nil {
563		ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedStringKeys(imageConfigs), ", "))
564		return nil
565	}
566	return imageConfig
567}
568
569// generateHiddenAPIBuildActions generates all the hidden API related build rules.
570func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput {
571
572	// Create hidden API input structure.
573	input := b.createHiddenAPIFlagInput(ctx, contents, fragments)
574
575	// Delegate the production of the hidden API all-flags.csv file to a module type specific method.
576	common := ctx.Module().(commonBootclasspathFragment)
577	output := common.produceHiddenAPIOutput(ctx, contents, input)
578
579	// Initialize a HiddenAPIInfo structure.
580	hiddenAPIInfo := HiddenAPIInfo{
581		// The monolithic hidden API processing needs access to the flag files that override the default
582		// flags from all the fragments whether or not they actually perform their own hidden API flag
583		// generation. That is because the monolithic hidden API processing uses those flag files to
584		// perform its own flag generation.
585		FlagFilesByCategory: input.FlagFilesByCategory,
586
587		// Other bootclasspath_fragments that depend on this need the transitive set of stub dex jars
588		// from this to resolve any references from their code to classes provided by this fragment
589		// and the fragments this depends upon.
590		TransitiveStubDexJarsByScope: input.transitiveStubDexJarsByScope(),
591	}
592
593	// The monolithic hidden API processing also needs access to all the output files produced by
594	// hidden API processing of this fragment.
595	hiddenAPIInfo.HiddenAPIFlagOutput = (*output).HiddenAPIFlagOutput
596
597	//  Provide it for use by other modules.
598	ctx.SetProvider(HiddenAPIInfoProvider, hiddenAPIInfo)
599
600	return output
601}
602
603// retrieveLegacyEncodedBootDexFiles attempts to retrieve the legacy encoded boot dex jar files.
604func retrieveLegacyEncodedBootDexFiles(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
605	// If the current bootclasspath_fragment is the active module or a source module then retrieve the
606	// encoded dex files, otherwise return an empty map.
607	//
608	// An inactive (i.e. not preferred) bootclasspath_fragment needs to retrieve the encoded dex jars
609	// as they are still needed by an apex. An inactive prebuilt_bootclasspath_fragment does not need
610	// to do so and may not yet have access to dex boot jars from a prebuilt_apex/apex_set.
611	if isActiveModule(ctx.Module()) || !android.IsModulePrebuilt(ctx.Module()) {
612		return extractEncodedDexJarsFromModules(ctx, contents)
613	} else {
614		return nil
615	}
616}
617
618// createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived
619// from the properties on this module and its dependencies.
620func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput {
621	// Merge the HiddenAPIInfo from all the fragment dependencies.
622	dependencyHiddenApiInfo := newHiddenAPIInfo()
623	dependencyHiddenApiInfo.mergeFromFragmentDeps(ctx, fragments)
624
625	// Create hidden API flag input structure.
626	input := newHiddenAPIFlagInput()
627
628	// Update the input structure with information obtained from the stub libraries.
629	input.gatherStubLibInfo(ctx, contents)
630
631	// Populate with flag file paths from the properties.
632	input.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api)
633
634	// Add the stub dex jars from this module's fragment dependencies.
635	input.DependencyStubDexJarsByScope.addStubDexJarsByModule(dependencyHiddenApiInfo.TransitiveStubDexJarsByScope)
636
637	return input
638}
639
640// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files)
641// for the fragment as well as encoding the flags in the boot dex jars.
642func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
643	// Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the
644	// paths to the created files.
645	return hiddenAPIRulesForBootclasspathFragment(ctx, contents, input)
646}
647
648// produceBootImageFiles builds the boot image files from the source if it is required.
649func (b *BootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch {
650	if SkipDexpreoptBootJars(ctx) {
651		return nil
652	}
653
654	// Only generate the boot image if the configuration does not skip it.
655	return b.generateBootImageBuildActions(ctx, imageConfig)
656}
657
658// generateBootImageBuildActions generates ninja rules to create the boot image if required for this
659// module.
660//
661// If it could not create the files then it will return nil. Otherwise, it will return a map from
662// android.ArchType to the predefined paths of the boot image files.
663func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch {
664	global := dexpreopt.GetGlobalConfig(ctx)
665	if !shouldBuildBootImages(ctx.Config(), global) {
666		return nil
667	}
668
669	// Bootclasspath fragment modules that are for the platform do not produce a boot image.
670	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
671	if apexInfo.IsForPlatform() {
672		return nil
673	}
674
675	// Bootclasspath fragment modules that are versioned do not produce a boot image.
676	if android.IsModuleInVersionedSdk(ctx.Module()) {
677		return nil
678	}
679
680	// Build a profile for the image config and then use that to build the boot image.
681	profile := bootImageProfileRule(ctx, imageConfig)
682
683	// Build boot image files for the host variants.
684	buildBootImageVariantsForBuildOs(ctx, imageConfig, profile)
685
686	// Build boot image files for the android variants.
687	androidBootImageFilesByArch := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile)
688
689	// Return the boot image files for the android variants for inclusion in an APEX and to be zipped
690	// up for the dist.
691	return androidBootImageFilesByArch
692}
693
694type bootclasspathFragmentMemberType struct {
695	android.SdkMemberTypeBase
696}
697
698func (b *bootclasspathFragmentMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
699	mctx.AddVariationDependencies(nil, dependencyTag, names...)
700}
701
702func (b *bootclasspathFragmentMemberType) IsInstance(module android.Module) bool {
703	_, ok := module.(*BootclasspathFragmentModule)
704	return ok
705}
706
707func (b *bootclasspathFragmentMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
708	if b.PropertyName == "boot_images" {
709		return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_boot_image")
710	} else {
711		return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_bootclasspath_fragment")
712	}
713}
714
715func (b *bootclasspathFragmentMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
716	return &bootclasspathFragmentSdkMemberProperties{}
717}
718
719type bootclasspathFragmentSdkMemberProperties struct {
720	android.SdkMemberPropertiesBase
721
722	// The image name
723	Image_name *string
724
725	// Contents of the bootclasspath fragment
726	Contents []string
727
728	// Stub_libs properties.
729	Stub_libs               []string
730	Core_platform_stub_libs []string
731
732	// Flag files by *hiddenAPIFlagFileCategory
733	Flag_files_by_category FlagFilesByCategory
734
735	// The path to the generated stub-flags.csv file.
736	Stub_flags_path android.OptionalPath
737
738	// The path to the generated annotation-flags.csv file.
739	Annotation_flags_path android.OptionalPath
740
741	// The path to the generated metadata.csv file.
742	Metadata_path android.OptionalPath
743
744	// The path to the generated index.csv file.
745	Index_path android.OptionalPath
746
747	// The path to the generated all-flags.csv file.
748	All_flags_path android.OptionalPath
749}
750
751func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
752	module := variant.(*BootclasspathFragmentModule)
753
754	b.Image_name = module.properties.Image_name
755	b.Contents = module.properties.Contents
756
757	// Get the hidden API information from the module.
758	mctx := ctx.SdkModuleContext()
759	hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoProvider).(HiddenAPIInfo)
760	b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory
761
762	// Copy all the generated file paths.
763	b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath)
764	b.Annotation_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AnnotationFlagsPath)
765	b.Metadata_path = android.OptionalPathForPath(hiddenAPIInfo.MetadataPath)
766	b.Index_path = android.OptionalPathForPath(hiddenAPIInfo.IndexPath)
767	b.All_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AllFlagsPath)
768
769	// Copy stub_libs properties.
770	b.Stub_libs = module.properties.Api.Stub_libs
771	b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs
772}
773
774func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
775	if b.Image_name != nil {
776		propertySet.AddProperty("image_name", *b.Image_name)
777	}
778
779	builder := ctx.SnapshotBuilder()
780	requiredMemberDependency := builder.SdkMemberReferencePropertyTag(true)
781
782	if len(b.Contents) > 0 {
783		propertySet.AddPropertyWithTag("contents", b.Contents, requiredMemberDependency)
784	}
785
786	if len(b.Stub_libs) > 0 {
787		apiPropertySet := propertySet.AddPropertySet("api")
788		apiPropertySet.AddPropertyWithTag("stub_libs", b.Stub_libs, requiredMemberDependency)
789	}
790	if len(b.Core_platform_stub_libs) > 0 {
791		corePlatformApiPropertySet := propertySet.AddPropertySet("core_platform_api")
792		corePlatformApiPropertySet.AddPropertyWithTag("stub_libs", b.Core_platform_stub_libs, requiredMemberDependency)
793	}
794
795	hiddenAPISet := propertySet.AddPropertySet("hidden_api")
796	hiddenAPIDir := "hiddenapi"
797
798	// Copy manually curated flag files specified on the bootclasspath_fragment.
799	if b.Flag_files_by_category != nil {
800		for _, category := range HiddenAPIFlagFileCategories {
801			paths := b.Flag_files_by_category[category]
802			if len(paths) > 0 {
803				dests := []string{}
804				for _, p := range paths {
805					dest := filepath.Join(hiddenAPIDir, p.Base())
806					builder.CopyToSnapshot(p, dest)
807					dests = append(dests, dest)
808				}
809				hiddenAPISet.AddProperty(category.PropertyName, dests)
810			}
811		}
812	}
813
814	copyOptionalPath := func(path android.OptionalPath, property string) {
815		if path.Valid() {
816			p := path.Path()
817			dest := filepath.Join(hiddenAPIDir, p.Base())
818			builder.CopyToSnapshot(p, dest)
819			hiddenAPISet.AddProperty(property, dest)
820		}
821	}
822
823	// Copy all the generated files, if available.
824	copyOptionalPath(b.Stub_flags_path, "stub_flags")
825	copyOptionalPath(b.Annotation_flags_path, "annotation_flags")
826	copyOptionalPath(b.Metadata_path, "metadata")
827	copyOptionalPath(b.Index_path, "index")
828	copyOptionalPath(b.All_flags_path, "all_flags")
829}
830
831var _ android.SdkMemberType = (*bootclasspathFragmentMemberType)(nil)
832
833// prebuiltBootclasspathFragmentProperties contains additional prebuilt_bootclasspath_fragment
834// specific properties.
835type prebuiltBootclasspathFragmentProperties struct {
836	Hidden_api struct {
837		// The path to the stub-flags.csv file created by the bootclasspath_fragment.
838		Stub_flags *string `android:"path"`
839
840		// The path to the annotation-flags.csv file created by the bootclasspath_fragment.
841		Annotation_flags *string `android:"path"`
842
843		// The path to the metadata.csv file created by the bootclasspath_fragment.
844		Metadata *string `android:"path"`
845
846		// The path to the index.csv file created by the bootclasspath_fragment.
847		Index *string `android:"path"`
848
849		// The path to the all-flags.csv file created by the bootclasspath_fragment.
850		All_flags *string `android:"path"`
851	}
852}
853
854// A prebuilt version of the bootclasspath_fragment module.
855//
856// At the moment this is basically just a bootclasspath_fragment module that can be used as a
857// prebuilt. Eventually as more functionality is migrated into the bootclasspath_fragment module
858// type from the various singletons then this will diverge.
859type prebuiltBootclasspathFragmentModule struct {
860	BootclasspathFragmentModule
861	prebuilt android.Prebuilt
862
863	// Additional prebuilt specific properties.
864	prebuiltProperties prebuiltBootclasspathFragmentProperties
865}
866
867func (module *prebuiltBootclasspathFragmentModule) Prebuilt() *android.Prebuilt {
868	return &module.prebuilt
869}
870
871func (module *prebuiltBootclasspathFragmentModule) Name() string {
872	return module.prebuilt.Name(module.ModuleBase.Name())
873}
874
875// produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified.
876func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
877	pathForOptionalSrc := func(src *string) android.Path {
878		if src == nil {
879			// TODO(b/179354495): Fail if this is not provided once prebuilts have been updated.
880			return nil
881		}
882		return android.PathForModuleSrc(ctx, *src)
883	}
884
885	// Retrieve the dex files directly from the content modules. They in turn should retrieve the
886	// encoded dex jars from the prebuilt .apex files.
887	encodedBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, contents)
888
889	output := HiddenAPIOutput{
890		HiddenAPIFlagOutput: HiddenAPIFlagOutput{
891			StubFlagsPath:       pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags),
892			AnnotationFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Annotation_flags),
893			MetadataPath:        pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Metadata),
894			IndexPath:           pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Index),
895			AllFlagsPath:        pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags),
896		},
897		EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
898	}
899
900	return &output
901}
902
903// produceBootImageFiles extracts the boot image files from the APEX if available.
904func (module *prebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch {
905	if !shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) {
906		return nil
907	}
908
909	var deapexerModule android.Module
910	ctx.VisitDirectDeps(func(to android.Module) {
911		tag := ctx.OtherModuleDependencyTag(to)
912		// Save away the `deapexer` module on which this depends, if any.
913		if tag == android.DeapexerTag {
914			if deapexerModule != nil {
915				ctx.ModuleErrorf("Ambiguous duplicate deapexer module dependencies %q and %q",
916					deapexerModule.Name(), to.Name())
917			}
918			deapexerModule = to
919		}
920	})
921
922	if deapexerModule == nil {
923		// This should never happen as a variant for a prebuilt_apex is only created if the
924		// deapexer module has been configured to export the dex implementation jar for this module.
925		ctx.ModuleErrorf("internal error: module does not depend on a `deapexer` module")
926		return nil
927	}
928
929	di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
930	files := bootImageFilesByArch{}
931	for _, variant := range imageConfig.apexVariants() {
932		arch := variant.target.Arch.ArchType
933		for _, toPath := range variant.imagesDeps {
934			apexRelativePath := apexRootRelativePathToBootImageFile(arch, toPath.Base())
935			// Get the path to the file that the deapexer extracted from the prebuilt apex file.
936			fromPath := di.PrebuiltExportPath(apexRelativePath)
937
938			// Return the toPath as the calling code expects the paths in the returned map to be the
939			// paths predefined in the bootImageConfig.
940			files[arch] = append(files[arch], toPath)
941
942			// Copy the file to the predefined location.
943			ctx.Build(pctx, android.BuildParams{
944				Rule:   android.Cp,
945				Input:  fromPath,
946				Output: toPath,
947			})
948		}
949	}
950
951	// Build the boot image files for the host variants. These are built from the dex files provided
952	// by the contents of this module as prebuilt versions of the host boot image files are not
953	// available, i.e. there is no host specific prebuilt apex containing them. This has to be built
954	// without a profile as the prebuilt modules do not provide a profile.
955	buildBootImageVariantsForBuildOs(ctx, imageConfig, nil)
956
957	return files
958}
959
960var _ commonBootclasspathFragment = (*prebuiltBootclasspathFragmentModule)(nil)
961
962// createBootImageTag creates the tag to uniquely identify the boot image file among all of the
963// files that a module requires from the prebuilt .apex file.
964func createBootImageTag(arch android.ArchType, baseName string) string {
965	tag := fmt.Sprintf(".bootimage-%s-%s", arch, baseName)
966	return tag
967}
968
969// RequiredFilesFromPrebuiltApex returns the list of all files the prebuilt_bootclasspath_fragment
970// requires from a prebuilt .apex file.
971//
972// If there is no image config associated with this fragment then it returns nil. Otherwise, it
973// returns the files that are listed in the image config.
974func (module *prebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
975	imageConfig := module.getImageConfig(ctx)
976	if imageConfig != nil {
977		// Add the boot image files, e.g. .art, .oat and .vdex files.
978		files := []string{}
979		for _, variant := range imageConfig.apexVariants() {
980			arch := variant.target.Arch.ArchType
981			for _, path := range variant.imagesDeps.Paths() {
982				base := path.Base()
983				files = append(files, apexRootRelativePathToBootImageFile(arch, base))
984			}
985		}
986		return files
987	}
988	return nil
989}
990
991func apexRootRelativePathToBootImageFile(arch android.ArchType, base string) string {
992	return filepath.Join("javalib", arch.String(), base)
993}
994
995var _ android.RequiredFilesFromPrebuiltApex = (*prebuiltBootclasspathFragmentModule)(nil)
996
997func prebuiltBootclasspathFragmentFactory() android.Module {
998	m := &prebuiltBootclasspathFragmentModule{}
999	m.AddProperties(&m.properties, &m.prebuiltProperties)
1000	// This doesn't actually have any prebuilt files of its own so pass a placeholder for the srcs
1001	// array.
1002	android.InitPrebuiltModule(m, &[]string{"placeholder"})
1003	android.InitApexModule(m)
1004	android.InitSdkAwareModule(m)
1005	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
1006
1007	// Initialize the contents property from the image_name.
1008	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
1009		bootclasspathFragmentInitContentsFromImage(ctx, &m.BootclasspathFragmentModule)
1010	})
1011	return m
1012}
1013