From 7b8455f5c23b600b117cde216280b584ca6b9a1d Mon Sep 17 00:00:00 2001 From: Wei Li Date: Wed, 5 Mar 2025 16:05:51 -0800 Subject: Add support for SBOM generation in soong-only builds Add an alternative way of collecting metadata in soong-only build, which is initially done in make. Bug: 398039178 Test: presubmits Test: lunch aosp_cf_x86_64_phone-trunk_staging-eng && m && m sbom Change-Id: I94476db21cf9eac8be7693043f2cd7a2b1bcd8a6 --- android/Android.bp | 1 + android/compliance_metadata.go | 42 ++++++++++++++++++++++++++++++++++++------ android/provider_keys.go | 24 ++++++++++++++++++++++++ filesystem/android_device.go | 26 ++++++++++++++++++++++++++ filesystem/bootimg.go | 5 +++++ filesystem/filesystem.go | 27 +++++++++++++++++++++++---- filesystem/super_image.go | 2 ++ fsgen/fsgen_mutators.go | 21 +++++++++++++++------ 8 files changed, 132 insertions(+), 16 deletions(-) create mode 100644 android/provider_keys.go diff --git a/android/Android.bp b/android/Android.bp index 1cc7ffe1d..00dc50ac2 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -97,6 +97,7 @@ bootstrap_go_package { "product_packages_file.go", "proto.go", "provider.go", + "provider_keys.go", "raw_files.go", "recovery_build_prop.go", "register.go", diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go index a6dbb8d17..7c0ab85c3 100644 --- a/android/compliance_metadata.go +++ b/android/compliance_metadata.go @@ -127,27 +127,32 @@ var ( // dependencies, built/installed files, etc. It is a wrapper on a map[string]string with some utility // methods to get/set properties' values. type ComplianceMetadataInfo struct { - properties map[string]string + properties map[string]string + filesContained []string } type complianceMetadataInfoGob struct { - Properties map[string]string + Properties map[string]string + FilesContained []string } func NewComplianceMetadataInfo() *ComplianceMetadataInfo { return &ComplianceMetadataInfo{ - properties: map[string]string{}, + properties: map[string]string{}, + filesContained: make([]string, 0), } } func (m *ComplianceMetadataInfo) ToGob() *complianceMetadataInfoGob { return &complianceMetadataInfoGob{ - Properties: m.properties, + Properties: m.properties, + FilesContained: m.filesContained, } } func (m *ComplianceMetadataInfo) FromGob(data *complianceMetadataInfoGob) { m.properties = data.Properties + m.filesContained = data.FilesContained } func (c *ComplianceMetadataInfo) GobEncode() ([]byte, error) { @@ -169,6 +174,14 @@ func (c *ComplianceMetadataInfo) SetListValue(propertyName string, value []strin c.SetStringValue(propertyName, strings.TrimSpace(strings.Join(value, " "))) } +func (c *ComplianceMetadataInfo) SetFilesContained(files []string) { + c.filesContained = files +} + +func (c *ComplianceMetadataInfo) GetFilesContained() []string { + return c.filesContained +} + func (c *ComplianceMetadataInfo) getStringValue(propertyName string) string { if !slices.Contains(COMPLIANCE_METADATA_PROPS, propertyName) { panic(fmt.Errorf("Unknown metadata property: %s.", propertyName)) @@ -317,8 +330,25 @@ func (c *complianceMetadataSingleton) GenerateBuildActions(ctx SingletonContext) makeModulesCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "make-modules.csv") if !ctx.Config().KatiEnabled() { - WriteFileRule(ctx, makeMetadataCsv, "installed_file,module_path,is_soong_module,is_prebuilt_make_module,product_copy_files,kernel_module_copy_files,is_platform_generated,static_libs,whole_static_libs,license_text") - WriteFileRule(ctx, makeModulesCsv, "name,module_path,module_class,module_type,static_libs,whole_static_libs,built_files,installed_files") + // In soong-only build the installed file list is from android_device module + ctx.VisitAllModuleProxies(func(module ModuleProxy) { + if androidDeviceInfo, ok := OtherModuleProvider(ctx, module, AndroidDeviceInfoProvider); !ok || !androidDeviceInfo.Main_device { + return + } + if metadataInfo, ok := OtherModuleProvider(ctx, module, ComplianceMetadataProvider); ok { + if len(metadataInfo.filesContained) > 0 { + csvHeaders := "installed_file,module_path,is_soong_module,is_prebuilt_make_module,product_copy_files,kernel_module_copy_files,is_platform_generated,static_libs,whole_static_libs,license_text" + csvContent := make([]string, 0, len(metadataInfo.filesContained)+1) + csvContent = append(csvContent, csvHeaders) + for _, file := range metadataInfo.filesContained { + csvContent = append(csvContent, file+",,Y,,,,,,,") + } + WriteFileRuleVerbatim(ctx, makeMetadataCsv, strings.Join(csvContent, "\n")) + WriteFileRuleVerbatim(ctx, makeModulesCsv, "name,module_path,module_class,module_type,static_libs,whole_static_libs,built_files,installed_files") + } + return + } + }) } // Import metadata from Make and Soong to sqlite3 database diff --git a/android/provider_keys.go b/android/provider_keys.go new file mode 100644 index 000000000..60b383f53 --- /dev/null +++ b/android/provider_keys.go @@ -0,0 +1,24 @@ +// Copyright 2025 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import "github.com/google/blueprint" + +// Providers of package filesystem +type AndroidDeviceInfo struct { + Main_device bool +} + +var AndroidDeviceInfoProvider = blueprint.NewProvider[AndroidDeviceInfo]() diff --git a/filesystem/android_device.go b/filesystem/android_device.go index 005dc3439..c49e53686 100644 --- a/filesystem/android_device.go +++ b/filesystem/android_device.go @@ -19,6 +19,7 @@ import ( "fmt" "path/filepath" "slices" + "sort" "strings" "sync/atomic" @@ -274,6 +275,31 @@ func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.setVbmetaPhonyTargets(ctx) a.distFiles(ctx) + + android.SetProvider(ctx, android.AndroidDeviceInfoProvider, android.AndroidDeviceInfo{ + Main_device: android.Bool(a.deviceProps.Main_device), + }) + + if proptools.String(a.partitionProps.Super_partition_name) != "" { + buildComplianceMetadata(ctx, superPartitionDepTag, filesystemDepTag) + } else { + buildComplianceMetadata(ctx, filesystemDepTag) + } +} + +func buildComplianceMetadata(ctx android.ModuleContext, tags ...blueprint.DependencyTag) { + filesContained := make([]string, 0) + for _, tag := range tags { + ctx.VisitDirectDepsProxyWithTag(tag, func(m android.ModuleProxy) { + if complianceMetadataInfo, ok := android.OtherModuleProvider(ctx, m, android.ComplianceMetadataProvider); ok { + filesContained = append(filesContained, complianceMetadataInfo.GetFilesContained()...) + } + }) + } + sort.Strings(filesContained) + + complianceMetadataInfo := ctx.ComplianceMetadataInfo() + complianceMetadataInfo.SetFilesContained(filesContained) } // Returns a list of modules that are installed, which are collected from the dependency diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go index effbd6542..2bf0d5905 100644 --- a/filesystem/bootimg.go +++ b/filesystem/bootimg.go @@ -263,6 +263,11 @@ func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) { PublicKey: extractedPublicKey, Output: output, }) + + // Dump compliance metadata + if ramdisk := proptools.String(b.properties.Ramdisk_module); ramdisk != "" { + buildComplianceMetadata(ctx, bootimgRamdiskDep) + } } var BootimgInfoProvider = blueprint.NewProvider[BootimgInfo]() diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index fc480e6f0..88de21792 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -695,6 +695,14 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { } f.setVbmetaPartitionProvider(ctx) + + // Dump metadata that can not be done in android/compliance-metadata.go + complianceMetadataInfo := ctx.ComplianceMetadataInfo() + filesContained := make([]string, 0, len(fullInstallPaths)) + for _, file := range fullInstallPaths { + filesContained = append(filesContained, file.FullInstallPath.String()) + } + complianceMetadataInfo.SetFilesContained(filesContained) } func (f *filesystem) fileystemStagingDirTimestamp(ctx android.ModuleContext) android.WritablePath { @@ -879,13 +887,24 @@ func (f *filesystem) buildNonDepsFiles( builder.Command().Text("mkdir -p").Text(filepath.Dir(dst.String())) builder.Command().Text("ln -sf").Text(proptools.ShellEscape(target)).Text(dst.String()) f.appendToEntry(ctx, dst) - // Only add the fullInstallPath logic for files in the rebased dir. The root dir - // is harder to install to. - if strings.HasPrefix(name, rebasedPrefix) { + // Add the fullInstallPath logic for files in the rebased dir, and for non-rebased files in "system" partition + // the fullInstallPath is changed to "root" which aligns to the behavior in Make. + if f.PartitionType() == "system" { + installPath := android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix)) + if !strings.HasPrefix(name, rebasedPrefix) { + installPath = android.PathForModuleInPartitionInstall(ctx, "root", name) + } *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ - FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix)), + FullInstallPath: installPath, SymlinkTarget: target, }) + } else { + if strings.HasPrefix(name, rebasedPrefix) { + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix)), + SymlinkTarget: target, + }) + } } } diff --git a/filesystem/super_image.go b/filesystem/super_image.go index 5e62fa702..9e4412c13 100644 --- a/filesystem/super_image.go +++ b/filesystem/super_image.go @@ -183,6 +183,8 @@ func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) { }) ctx.SetOutputFiles([]android.Path{output}, "") ctx.CheckbuildFile(output) + + buildComplianceMetadata(ctx, subImageDepTag) } func (s *superImage) installFileName() string { diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go index 9b25e77a5..d34ae77a6 100644 --- a/fsgen/fsgen_mutators.go +++ b/fsgen/fsgen_mutators.go @@ -105,12 +105,14 @@ func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNam "libgsi": defaultDepCandidateProps(ctx.Config()), "llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()), "logpersist.start": defaultDepCandidateProps(ctx.Config()), + "notice_xml_system": defaultDepCandidateProps(ctx.Config()), "update_engine_sideload": defaultDepCandidateProps(ctx.Config()), // keep-sorted end }, "vendor": { "fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()), "fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()), + "notice_xml_vendor": defaultDepCandidateProps(ctx.Config()), generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()), }, "odm": { @@ -118,34 +120,41 @@ func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNam // https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0 "fs_config_files_odm": defaultDepCandidateProps(ctx.Config()), "fs_config_dirs_odm": defaultDepCandidateProps(ctx.Config()), + "notice_xml_odm": defaultDepCandidateProps(ctx.Config()), + }, + "product": { + "notice_xml_product": defaultDepCandidateProps(ctx.Config()), }, - "product": {}, "system_ext": { // VNDK apexes are automatically included. // This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated. // https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7 - "com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()), - "com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()), - "com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()), - "com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()), - "com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()), + "com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()), + "com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()), + "com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()), + "com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()), + "com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()), + "notice_xml_system_ext": defaultDepCandidateProps(ctx.Config()), }, "userdata": {}, "system_dlkm": { // these are phony required deps of the phony fs_config_dirs_nonsystem "fs_config_dirs_system_dlkm": defaultDepCandidateProps(ctx.Config()), "fs_config_files_system_dlkm": defaultDepCandidateProps(ctx.Config()), + "notice_xml_system_dlkm": defaultDepCandidateProps(ctx.Config()), // build props are automatically added to `ALL_DEFAULT_INSTALLED_MODULES` "system_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()), }, "vendor_dlkm": { "fs_config_dirs_vendor_dlkm": defaultDepCandidateProps(ctx.Config()), "fs_config_files_vendor_dlkm": defaultDepCandidateProps(ctx.Config()), + "notice_xml_vendor_dlkm": defaultDepCandidateProps(ctx.Config()), "vendor_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()), }, "odm_dlkm": { "fs_config_dirs_odm_dlkm": defaultDepCandidateProps(ctx.Config()), "fs_config_files_odm_dlkm": defaultDepCandidateProps(ctx.Config()), + "notice_xml_odm_dlkm": defaultDepCandidateProps(ctx.Config()), "odm_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()), }, "ramdisk": {}, -- cgit v1.2.3-59-g8ed1b