From 48f3778cb4b86a3d5827ba4b020157ace975917b Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Wed, 7 Jul 2021 12:42:39 +0900 Subject: [PATCH] Separate snapshot definition Current snapshot definition is located in the CC module, so it is difficult to capture non-CC module (such as prebuilt_etc) to the snapshot. Separate general snapshot definition from cc so other modules can also define its own snapshot. Bug: 192430376 Test: m nothing passed Change-Id: Ifb69fb3d2ec555b629aa31ec03e7ce5831fd3063 --- cc/Android.bp | 1 + cc/genrule.go | 5 +- cc/image.go | 7 +- cc/linkable.go | 10 +- cc/sanitize.go | 3 +- cc/sdk.go | 2 +- cc/snapshot_prebuilt.go | 290 +++++++--------------------------- cc/snapshot_utils.go | 2 +- cc/testing.go | 13 +- cc/vendor_snapshot.go | 208 ++++-------------------- rust/Android.bp | 1 + rust/library.go | 3 +- rust/snapshot_prebuilt.go | 1 + snapshot/Android.bp | 21 +++ snapshot/recovery_snapshot.go | 130 +++++++++++++++ snapshot/snapshot.go | 122 ++++++++++++++ snapshot/snapshot_base.go | 104 ++++++++++++ snapshot/vendor_snapshot.go | 147 +++++++++++++++++ 18 files changed, 643 insertions(+), 427 deletions(-) create mode 100644 snapshot/Android.bp create mode 100644 snapshot/recovery_snapshot.go create mode 100644 snapshot/snapshot.go create mode 100644 snapshot/snapshot_base.go create mode 100644 snapshot/vendor_snapshot.go diff --git a/cc/Android.bp b/cc/Android.bp index 46740dcf2..05fff1244 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -14,6 +14,7 @@ bootstrap_go_package { "soong-cc-config", "soong-etc", "soong-genrule", + "soong-snapshot", "soong-tradefed", ], srcs: [ diff --git a/cc/genrule.go b/cc/genrule.go index b0efc6ca4..0ca901e61 100644 --- a/cc/genrule.go +++ b/cc/genrule.go @@ -17,6 +17,7 @@ package cc import ( "android/soong/android" "android/soong/genrule" + "android/soong/snapshot" ) func init() { @@ -84,7 +85,7 @@ func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleCon // is not needed. recoverySnapshotVersion := ctx.DeviceConfig().RecoverySnapshotVersion() if recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && - !isRecoveryProprietaryModule(ctx) { + !snapshot.IsRecoveryProprietaryModule(ctx) { return false } else { return Bool(g.Recovery_available) @@ -103,7 +104,7 @@ func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleCont // If not, we assume modules under proprietary paths are compatible for // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is // PLATFORM_VNDK_VERSION. - if vndkVersion == "current" || !IsVendorProprietaryModule(ctx) { + if vndkVersion == "current" || !snapshot.IsVendorProprietaryModule(ctx) { variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion()) } else { variants = append(variants, VendorVariationPrefix+vndkVersion) diff --git a/cc/image.go b/cc/image.go index 15ec1c867..3a0857b21 100644 --- a/cc/image.go +++ b/cc/image.go @@ -22,6 +22,7 @@ import ( "strings" "android/soong/android" + "android/soong/snapshot" ) var _ android.ImageInterface = (*Module)(nil) @@ -496,7 +497,7 @@ func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) { // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or // PLATFORM_VNDK_VERSION. if m.HasVendorVariant() { - if IsVendorProprietaryModule(mctx) { + if snapshot.IsVendorProprietaryModule(mctx) { vendorVariants = append(vendorVariants, boardVndkVersion) } else { vendorVariants = append(vendorVariants, platformVndkVersion) @@ -525,7 +526,7 @@ func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) { platformVndkVersion, boardVndkVersion, ) - } else if IsVendorProprietaryModule(mctx) { + } else if snapshot.IsVendorProprietaryModule(mctx) { vendorVariants = append(vendorVariants, boardVndkVersion) } else { vendorVariants = append(vendorVariants, platformVndkVersion) @@ -582,7 +583,7 @@ func MutateImage(mctx android.BaseModuleContext, m ImageMutatableModule) { if !m.KernelHeadersDecorator() && !m.IsSnapshotPrebuilt() && usingRecoverySnapshot && - !isRecoveryProprietaryModule(mctx) { + !snapshot.IsRecoveryProprietaryModule(mctx) { recoveryVariantNeeded = false } diff --git a/cc/linkable.go b/cc/linkable.go index 6232efb95..b510508a7 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -3,6 +3,7 @@ package cc import ( "android/soong/android" "android/soong/bazel/cquery" + "android/soong/snapshot" "github.com/google/blueprint" ) @@ -71,15 +72,12 @@ type SantizableDependencyTagChecker func(tag blueprint.DependencyTag) bool // Snapshottable defines those functions necessary for handling module snapshots. type Snapshottable interface { + snapshot.VendorSnapshotModuleInterface + snapshot.RecoverySnapshotModuleInterface + // SnapshotHeaders returns a list of header paths provided by this module. SnapshotHeaders() android.Paths - // ExcludeFromVendorSnapshot returns true if this module should be otherwise excluded from the vendor snapshot. - ExcludeFromVendorSnapshot() bool - - // ExcludeFromRecoverySnapshot returns true if this module should be otherwise excluded from the recovery snapshot. - ExcludeFromRecoverySnapshot() bool - // SnapshotLibrary returns true if this module is a snapshot library. IsSnapshotLibrary() bool diff --git a/cc/sanitize.go b/cc/sanitize.go index defe8fde1..3863c3a7c 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -25,6 +25,7 @@ import ( "android/soong/android" "android/soong/cc/config" + "android/soong/snapshot" ) var ( @@ -907,7 +908,7 @@ func (m *Module) SanitizableDepTagChecker() SantizableDependencyTagChecker { // as vendor snapshot. Such modules must create both cfi and non-cfi variants, // except for ones which explicitly disable cfi. func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool { - if IsVendorProprietaryModule(mctx) { + if snapshot.IsVendorProprietaryModule(mctx) { return false } diff --git a/cc/sdk.go b/cc/sdk.go index 69ad311e2..a83e5ad2a 100644 --- a/cc/sdk.go +++ b/cc/sdk.go @@ -76,7 +76,7 @@ func sdkMutator(ctx android.BottomUpMutatorContext) { } ctx.AliasVariation("") } - case *snapshot: + case *snapshotModule: ctx.CreateVariations("") } } diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index 4f031ff96..9672c0fff 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -18,57 +18,17 @@ package cc // snapshot mutators and snapshot information maps which are also defined in this file. import ( - "path/filepath" "strings" "android/soong/android" + "android/soong/snapshot" "github.com/google/blueprint" ) -// Defines the specifics of different images to which the snapshot process is applicable, e.g., -// vendor, recovery, ramdisk. +// This interface overrides snapshot.SnapshotImage to implement cc module specific functions type SnapshotImage interface { - // Returns true if a snapshot should be generated for this image. - shouldGenerateSnapshot(ctx android.SingletonContext) bool - - // Function that returns true if the module is included in this image. - // Using a function return instead of a value to prevent early - // evalution of a function that may be not be defined. - inImage(m LinkableInterface) func() bool - - // Returns true if the module is private and must not be included in the - // snapshot. For example VNDK-private modules must return true for the - // vendor snapshots. But false for the recovery snapshots. - private(m LinkableInterface) bool - - // Returns true if a dir under source tree is an SoC-owned proprietary - // directory, such as device/, vendor/, etc. - // - // For a given snapshot (e.g., vendor, recovery, etc.) if - // isProprietaryPath(dir, deviceConfig) returns true, then the module in dir - // will be built from sources. - isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool - - // Whether to include VNDK in the snapshot for this image. - includeVndk() bool - - // Whether a given module has been explicitly excluded from the - // snapshot, e.g., using the exclude_from_vendor_snapshot or - // exclude_from_recovery_snapshot properties. - excludeFromSnapshot(m LinkableInterface) bool - - // Returns true if the build is using a snapshot for this image. - isUsingSnapshot(cfg android.DeviceConfig) bool - - // Returns a version of which the snapshot should be used in this target. - // This will only be meaningful when isUsingSnapshot is true. - targetSnapshotVersion(cfg android.DeviceConfig) string - - // Whether to exclude a given module from the directed snapshot or not. - // If the makefile variable DIRECTED_{IMAGE}_SNAPSHOT is true, directed snapshot is turned on, - // and only modules listed in {IMAGE}_SNAPSHOT_MODULES will be captured. - excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool + snapshot.SnapshotImage // The image variant name for this snapshot image. // For example, recovery snapshot image will return "recovery", and vendor snapshot image will @@ -80,110 +40,12 @@ type SnapshotImage interface { moduleNameSuffix() string } -type vendorSnapshotImage struct{} -type recoverySnapshotImage struct{} - -type directoryMap map[string]bool - -var ( - // Modules under following directories are ignored. They are OEM's and vendor's - // proprietary modules(device/, kernel/, vendor/, and hardware/). - defaultDirectoryExcludedMap = directoryMap{ - "device": true, - "hardware": true, - "kernel": true, - "vendor": true, - } - - // Modules under following directories are included as they are in AOSP, - // although hardware/ and kernel/ are normally for vendor's own. - defaultDirectoryIncludedMap = directoryMap{ - "kernel/configs": true, - "kernel/prebuilts": true, - "kernel/tests": true, - "hardware/interfaces": true, - "hardware/libhardware": true, - "hardware/libhardware_legacy": true, - "hardware/ril": true, - } -) - -func (vendorSnapshotImage) Init(ctx android.RegistrationContext) { - ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton) - ctx.RegisterModuleType("vendor_snapshot", vendorSnapshotFactory) - ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory) - ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) - ctx.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory) - ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory) - ctx.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory) - - ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton) +type vendorSnapshotImage struct { + *snapshot.VendorSnapshotImage } -func (vendorSnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) { - ctx.RegisterModuleType(name, factory) -} - -func (vendorSnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool { - // BOARD_VNDK_VERSION must be set to 'current' in order to generate a snapshot. - return ctx.DeviceConfig().VndkVersion() == "current" -} - -func (vendorSnapshotImage) inImage(m LinkableInterface) func() bool { - return m.InVendor -} - -func (vendorSnapshotImage) private(m LinkableInterface) bool { - return m.IsVndkPrivate() -} - -func isDirectoryExcluded(dir string, excludedMap directoryMap, includedMap directoryMap) bool { - if dir == "." || dir == "/" { - return false - } - if includedMap[dir] { - return false - } else if excludedMap[dir] { - return true - } else if defaultDirectoryIncludedMap[dir] { - return false - } else if defaultDirectoryExcludedMap[dir] { - return true - } else { - return isDirectoryExcluded(filepath.Dir(dir), excludedMap, includedMap) - } -} - -func (vendorSnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { - return isDirectoryExcluded(dir, deviceConfig.VendorSnapshotDirsExcludedMap(), deviceConfig.VendorSnapshotDirsIncludedMap()) -} - -// vendor snapshot includes static/header libraries with vndk: {enabled: true}. -func (vendorSnapshotImage) includeVndk() bool { - return true -} - -func (vendorSnapshotImage) excludeFromSnapshot(m LinkableInterface) bool { - return m.ExcludeFromVendorSnapshot() -} - -func (vendorSnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool { - vndkVersion := cfg.VndkVersion() - return vndkVersion != "current" && vndkVersion != "" -} - -func (vendorSnapshotImage) targetSnapshotVersion(cfg android.DeviceConfig) string { - return cfg.VndkVersion() -} - -// returns true iff a given module SHOULD BE EXCLUDED, false if included -func (vendorSnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool { - // If we're using full snapshot, not directed snapshot, capture every module - if !cfg.DirectedVendorSnapshot() { - return false - } - // Else, checks if name is in VENDOR_SNAPSHOT_MODULES. - return !cfg.VendorSnapshotModules()[name] +type recoverySnapshotImage struct { + *snapshot.RecoverySnapshotImage } func (vendorSnapshotImage) imageVariantName(cfg android.DeviceConfig) string { @@ -194,62 +56,6 @@ func (vendorSnapshotImage) moduleNameSuffix() string { return VendorSuffix } -func (recoverySnapshotImage) init(ctx android.RegistrationContext) { - ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton) - ctx.RegisterModuleType("recovery_snapshot", recoverySnapshotFactory) - ctx.RegisterModuleType("recovery_snapshot_shared", RecoverySnapshotSharedFactory) - ctx.RegisterModuleType("recovery_snapshot_static", RecoverySnapshotStaticFactory) - ctx.RegisterModuleType("recovery_snapshot_header", RecoverySnapshotHeaderFactory) - ctx.RegisterModuleType("recovery_snapshot_binary", RecoverySnapshotBinaryFactory) - ctx.RegisterModuleType("recovery_snapshot_object", RecoverySnapshotObjectFactory) -} - -func (recoverySnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool { - // RECOVERY_SNAPSHOT_VERSION must be set to 'current' in order to generate a - // snapshot. - return ctx.DeviceConfig().RecoverySnapshotVersion() == "current" -} - -func (recoverySnapshotImage) inImage(m LinkableInterface) func() bool { - return m.InRecovery -} - -// recovery snapshot does not have private libraries. -func (recoverySnapshotImage) private(m LinkableInterface) bool { - return false -} - -func (recoverySnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { - return isDirectoryExcluded(dir, deviceConfig.RecoverySnapshotDirsExcludedMap(), deviceConfig.RecoverySnapshotDirsIncludedMap()) -} - -// recovery snapshot does NOT treat vndk specially. -func (recoverySnapshotImage) includeVndk() bool { - return false -} - -func (recoverySnapshotImage) excludeFromSnapshot(m LinkableInterface) bool { - return m.ExcludeFromRecoverySnapshot() -} - -func (recoverySnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool { - recoverySnapshotVersion := cfg.RecoverySnapshotVersion() - return recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" -} - -func (recoverySnapshotImage) targetSnapshotVersion(cfg android.DeviceConfig) string { - return cfg.RecoverySnapshotVersion() -} - -func (recoverySnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool { - // If we're using full snapshot, not directed snapshot, capture every module - if !cfg.DirectedRecoverySnapshot() { - return false - } - // Else, checks if name is in RECOVERY_SNAPSHOT_MODULES. - return !cfg.RecoverySnapshotModules()[name] -} - func (recoverySnapshotImage) imageVariantName(cfg android.DeviceConfig) string { return android.RecoveryVariation } @@ -258,12 +64,31 @@ func (recoverySnapshotImage) moduleNameSuffix() string { return recoverySuffix } -var VendorSnapshotImageSingleton vendorSnapshotImage -var recoverySnapshotImageSingleton recoverySnapshotImage +// Override existing vendor and recovery snapshot for cc module specific extra functions +var VendorSnapshotImageSingleton vendorSnapshotImage = vendorSnapshotImage{&snapshot.VendorSnapshotImageSingleton} +var recoverySnapshotImageSingleton recoverySnapshotImage = recoverySnapshotImage{&snapshot.RecoverySnapshotImageSingleton} + +func RegisterVendorSnapshotModules(ctx android.RegistrationContext) { + ctx.RegisterModuleType("vendor_snapshot", vendorSnapshotFactory) + ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory) + ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) + ctx.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory) + ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory) + ctx.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory) +} + +func RegisterRecoverySnapshotModules(ctx android.RegistrationContext) { + ctx.RegisterModuleType("recovery_snapshot", recoverySnapshotFactory) + ctx.RegisterModuleType("recovery_snapshot_shared", RecoverySnapshotSharedFactory) + ctx.RegisterModuleType("recovery_snapshot_static", RecoverySnapshotStaticFactory) + ctx.RegisterModuleType("recovery_snapshot_header", RecoverySnapshotHeaderFactory) + ctx.RegisterModuleType("recovery_snapshot_binary", RecoverySnapshotBinaryFactory) + ctx.RegisterModuleType("recovery_snapshot_object", RecoverySnapshotObjectFactory) +} func init() { - VendorSnapshotImageSingleton.Init(android.InitRegistrationContext) - recoverySnapshotImageSingleton.init(android.InitRegistrationContext) + RegisterVendorSnapshotModules(android.InitRegistrationContext) + RegisterRecoverySnapshotModules(android.InitRegistrationContext) android.RegisterMakeVarsProvider(pctx, snapshotMakeVarsProvider) } @@ -285,8 +110,7 @@ type SnapshotProperties struct { Binaries []string `android:"arch_variant"` Objects []string `android:"arch_variant"` } - -type snapshot struct { +type snapshotModule struct { android.ModuleBase properties SnapshotProperties @@ -296,41 +120,41 @@ type snapshot struct { image SnapshotImage } -func (s *snapshot) ImageMutatorBegin(ctx android.BaseModuleContext) { +func (s *snapshotModule) ImageMutatorBegin(ctx android.BaseModuleContext) { cfg := ctx.DeviceConfig() - if !s.image.isUsingSnapshot(cfg) || s.image.targetSnapshotVersion(cfg) != s.baseSnapshot.Version() { + if !s.image.IsUsingSnapshot(cfg) || s.image.TargetSnapshotVersion(cfg) != s.baseSnapshot.Version() { s.Disable() } } -func (s *snapshot) CoreVariantNeeded(ctx android.BaseModuleContext) bool { +func (s *snapshotModule) CoreVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (s *snapshot) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { +func (s *snapshotModule) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (s *snapshot) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { +func (s *snapshotModule) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (s *snapshot) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { +func (s *snapshotModule) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (s *snapshot) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { +func (s *snapshotModule) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { return false } -func (s *snapshot) ExtraImageVariations(ctx android.BaseModuleContext) []string { +func (s *snapshotModule) ExtraImageVariations(ctx android.BaseModuleContext) []string { return []string{s.image.imageVariantName(ctx.DeviceConfig())} } -func (s *snapshot) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { +func (s *snapshotModule) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { } -func (s *snapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) { +func (s *snapshotModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Nothing, the snapshot module is only used to forward dependency information in DepsMutator. } @@ -342,7 +166,7 @@ func getSnapshotNameSuffix(moduleSuffix, version, arch string) string { return moduleSuffix + versionSuffix } -func (s *snapshot) DepsMutator(ctx android.BottomUpMutatorContext) { +func (s *snapshotModule) DepsMutator(ctx android.BottomUpMutatorContext) { collectSnapshotMap := func(names []string, snapshotSuffix, moduleSuffix string) map[string]string { snapshotMap := make(map[string]string) for _, name := range names { @@ -382,12 +206,12 @@ type SnapshotInfo struct { var SnapshotInfoProvider = blueprint.NewMutatorProvider(SnapshotInfo{}, "deps") -var _ android.ImageInterface = (*snapshot)(nil) +var _ android.ImageInterface = (*snapshotModule)(nil) func snapshotMakeVarsProvider(ctx android.MakeVarsContext) { snapshotSet := map[string]struct{}{} ctx.VisitAllModules(func(m android.Module) { - if s, ok := m.(*snapshot); ok { + if s, ok := m.(*snapshotModule); ok { if _, ok := snapshotSet[s.Name()]; ok { // arch variant generates duplicated modules // skip this as we only need to know the path of the module. @@ -411,13 +235,13 @@ func recoverySnapshotFactory() android.Module { } func snapshotFactory(image SnapshotImage) android.Module { - snapshot := &snapshot{} - snapshot.image = image - snapshot.AddProperties( - &snapshot.properties, - &snapshot.baseSnapshot.baseProperties) - android.InitAndroidArchModule(snapshot, android.DeviceSupported, android.MultilibBoth) - return snapshot + snapshotModule := &snapshotModule{} + snapshotModule.image = image + snapshotModule.AddProperties( + &snapshotModule.properties, + &snapshotModule.baseSnapshot.baseProperties) + android.InitAndroidArchModule(snapshotModule, android.DeviceSupported, android.MultilibBoth) + return snapshotModule } type BaseSnapshotDecoratorProperties struct { @@ -449,7 +273,7 @@ type BaseSnapshotDecoratorProperties struct { // will be seen as "libbase.vendor_static.30.arm64" by Soong. type BaseSnapshotDecorator struct { baseProperties BaseSnapshotDecoratorProperties - image SnapshotImage + Image SnapshotImage } func (p *BaseSnapshotDecorator) Name(name string) string { @@ -489,7 +313,7 @@ func (p *BaseSnapshotDecorator) SetSnapshotAndroidMkSuffix(ctx android.ModuleCon Variation: android.CoreVariation}) if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) { - p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix() + p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix() return } @@ -498,14 +322,14 @@ func (p *BaseSnapshotDecorator) SetSnapshotAndroidMkSuffix(ctx android.ModuleCon Variation: ProductVariationPrefix + ctx.DeviceConfig().PlatformVndkVersion()}) if ctx.OtherModuleFarDependencyVariantExists(variations, ctx.Module().(LinkableInterface).BaseModuleName()) { - p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix() + p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix() return } images := []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton} for _, image := range images { - if p.image == image { + if p.Image == image { continue } variations = append(ctx.Target().Variations(), blueprint.Variation{ @@ -518,7 +342,7 @@ func (p *BaseSnapshotDecorator) SetSnapshotAndroidMkSuffix(ctx android.ModuleCon image.moduleNameSuffix()+variant, p.Version(), ctx.DeviceConfig().Arches()[0].ArchType.String())) { - p.baseProperties.Androidmk_suffix = p.image.moduleNameSuffix() + p.baseProperties.Androidmk_suffix = p.Image.moduleNameSuffix() return } } @@ -529,7 +353,7 @@ func (p *BaseSnapshotDecorator) SetSnapshotAndroidMkSuffix(ctx android.ModuleCon // Call this with a module suffix after creating a snapshot module, such as // vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc. func (p *BaseSnapshotDecorator) Init(m LinkableInterface, image SnapshotImage, moduleSuffix string) { - p.image = image + p.Image = image p.baseProperties.ModuleSuffix = image.moduleNameSuffix() + moduleSuffix m.AddProperties(&p.baseProperties) android.AddLoadHook(m, func(ctx android.LoadHookContext) { diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go index b0538bea0..24abcce55 100644 --- a/cc/snapshot_utils.go +++ b/cc/snapshot_utils.go @@ -114,7 +114,7 @@ func ShouldCollectHeadersForSnapshot(ctx android.ModuleContext, m LinkableInterf } for _, image := range []SnapshotImage{VendorSnapshotImageSingleton, recoverySnapshotImageSingleton} { - if isSnapshotAware(ctx.DeviceConfig(), m, image.isProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) { + if isSnapshotAware(ctx.DeviceConfig(), m, image.IsProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) { return true } } diff --git a/cc/testing.go b/cc/testing.go index b9d84f6cb..6a002c05a 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -20,6 +20,7 @@ import ( "android/soong/android" "android/soong/genrule" + "android/soong/snapshot" ) func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { @@ -638,8 +639,10 @@ var PrepareForTestOnFuchsia = android.GroupFixturePreparers( var PrepareForTestWithCcIncludeVndk = android.GroupFixturePreparers( PrepareForIntegrationTestWithCc, android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { - VendorSnapshotImageSingleton.Init(ctx) - recoverySnapshotImageSingleton.init(ctx) + snapshot.VendorSnapshotImageSingleton.Init(ctx) + snapshot.RecoverySnapshotImageSingleton.Init(ctx) + RegisterVendorSnapshotModules(ctx) + RegisterRecoverySnapshotModules(ctx) ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) }), ) @@ -687,8 +690,10 @@ func CreateTestContext(config android.Config) *android.TestContext { ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) - VendorSnapshotImageSingleton.Init(ctx) - recoverySnapshotImageSingleton.init(ctx) + snapshot.VendorSnapshotImageSingleton.Init(ctx) + snapshot.RecoverySnapshotImageSingleton.Init(ctx) + RegisterVendorSnapshotModules(ctx) + RegisterRecoverySnapshotModules(ctx) ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton) RegisterVndkLibraryTxtTypes(ctx) diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index 003b7c98b..6705d557b 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -13,141 +13,46 @@ // limitations under the License. package cc -// This file contains singletons to capture vendor and recovery snapshot. They consist of prebuilt -// modules under AOSP so older vendor and recovery can be built with a newer system in a single -// source tree. - import ( "encoding/json" "path/filepath" - "sort" "strings" "android/soong/android" + "android/soong/snapshot" ) -var vendorSnapshotSingleton = snapshotSingleton{ - "vendor", - "SOONG_VENDOR_SNAPSHOT_ZIP", - android.OptionalPath{}, - true, - VendorSnapshotImageSingleton, - false, /* fake */ -} +// This file defines how to capture cc modules into snapshot package. -var vendorFakeSnapshotSingleton = snapshotSingleton{ - "vendor", - "SOONG_VENDOR_FAKE_SNAPSHOT_ZIP", - android.OptionalPath{}, - true, - VendorSnapshotImageSingleton, - true, /* fake */ -} - -var recoverySnapshotSingleton = snapshotSingleton{ - "recovery", - "SOONG_RECOVERY_SNAPSHOT_ZIP", - android.OptionalPath{}, - false, - recoverySnapshotImageSingleton, - false, /* fake */ -} - -func VendorSnapshotSingleton() android.Singleton { - return &vendorSnapshotSingleton -} - -func VendorFakeSnapshotSingleton() android.Singleton { - return &vendorFakeSnapshotSingleton -} - -func RecoverySnapshotSingleton() android.Singleton { - return &recoverySnapshotSingleton -} - -type snapshotSingleton struct { - // Name, e.g., "vendor", "recovery", "ramdisk". - name string - - // Make variable that points to the snapshot file, e.g., - // "SOONG_RECOVERY_SNAPSHOT_ZIP". - makeVar string - - // Path to the snapshot zip file. - snapshotZipFile android.OptionalPath - - // Whether the image supports VNDK extension modules. - supportsVndkExt bool - - // Implementation of the image interface specific to the image - // associated with this snapshot (e.g., specific to the vendor image, - // recovery image, etc.). - image SnapshotImage - - // Whether this singleton is for fake snapshot or not. - // Fake snapshot is a snapshot whose prebuilt binaries and headers are empty. - // It is much faster to generate, and can be used to inspect dependencies. - fake bool -} - -// Determine if a dir under source tree is an SoC-owned proprietary directory based -// on vendor snapshot configuration -// Examples: device/, vendor/ -func isVendorProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { - return VendorSnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig) -} - -// Determine if a dir under source tree is an SoC-owned proprietary directory based -// on recovery snapshot configuration -// Examples: device/, vendor/ -func isRecoveryProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { - return RecoverySnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig) -} - -func IsVendorProprietaryModule(ctx android.BaseModuleContext) bool { - // Any module in a vendor proprietary path is a vendor proprietary - // module. - if isVendorProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) { +// Checks if the target image would contain VNDK +func includeVndk(image snapshot.SnapshotImage) bool { + if image.ImageName() == snapshot.VendorSnapshotImageName { return true } - // However if the module is not in a vendor proprietary path, it may - // still be a vendor proprietary module. This happens for cc modules - // that are excluded from the vendor snapshot, and it means that the - // vendor has assumed control of the framework-provided module. - if c, ok := ctx.Module().(LinkableInterface); ok { - if c.ExcludeFromVendorSnapshot() { - return true - } - } - return false } -func isRecoveryProprietaryModule(ctx android.BaseModuleContext) bool { - - // Any module in a recovery proprietary path is a recovery proprietary - // module. - if isRecoveryProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) { +// Check if the module is VNDK private +func isPrivate(image snapshot.SnapshotImage, m LinkableInterface) bool { + if image.ImageName() == snapshot.VendorSnapshotImageName && m.IsVndkPrivate() { return true } - // However if the module is not in a recovery proprietary path, it may - // still be a recovery proprietary module. This happens for cc modules - // that are excluded from the recovery snapshot, and it means that the - // vendor has assumed control of the framework-provided module. + return false +} - if c, ok := ctx.Module().(LinkableInterface); ok { - if c.ExcludeFromRecoverySnapshot() { - return true - } +// Checks if target image supports VNDK Ext +func supportsVndkExt(image snapshot.SnapshotImage) bool { + if image.ImageName() == snapshot.VendorSnapshotImageName { + return true } return false } // Determines if the module is a candidate for snapshot. -func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image SnapshotImage) bool { +func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietaryPath bool, apexInfo android.ApexInfo, image snapshot.SnapshotImage) bool { if !m.Enabled() || m.HiddenFromMake() { return false } @@ -158,12 +63,12 @@ func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietar } // skip proprietary modules, but (for the vendor snapshot only) // include all VNDK (static) - if inProprietaryPath && (!image.includeVndk() || !m.IsVndk()) { + if inProprietaryPath && (!includeVndk(image) || !m.IsVndk()) { return false } // If the module would be included based on its path, check to see if // the module is marked to be excluded. If so, skip it. - if image.excludeFromSnapshot(m) { + if image.ExcludeFromSnapshot(m) { return false } if m.Target().Os.Class != android.Device { @@ -173,7 +78,7 @@ func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietar return false } // the module must be installed in target image - if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.inImage(m)() { + if !apexInfo.IsForPlatform() || m.IsSnapshotPrebuilt() || !image.InImage(m)() { return false } // skip kernel_headers which always depend on vendor @@ -203,13 +108,13 @@ func isSnapshotAware(cfg android.DeviceConfig, m LinkableInterface, inProprietar } } if sanitizable.Static() { - return sanitizable.OutputFile().Valid() && !image.private(m) + return sanitizable.OutputFile().Valid() && !isPrivate(image, m) } if sanitizable.Shared() || sanitizable.Rlib() { if !sanitizable.OutputFile().Valid() { return false } - if image.includeVndk() { + if includeVndk(image) { if !sanitizable.IsVndk() { return true } @@ -256,15 +161,9 @@ type snapshotJsonFlags struct { VintfFragments []string `json:",omitempty"` } -func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { - if !c.image.shouldGenerateSnapshot(ctx) { - return - } - - var snapshotOutputs android.Paths - +var ccSnapshotAction snapshot.GenerateSnapshotAction = func(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths { /* - Vendor snapshot zipped artifacts directory structure: + Vendor snapshot zipped artifacts directory structure for cc modules: {SNAPSHOT_ARCH}/ arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/ shared/ @@ -296,13 +195,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { (header files of same directory structure with source tree) */ - snapshotDir := c.name + "-snapshot" - if c.fake { - // If this is a fake snapshot singleton, place all files under fake/ subdirectory to avoid - // collision with real snapshot files - snapshotDir = filepath.Join("fake", snapshotDir) - } - snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch()) + var snapshotOutputs android.Paths includeDir := filepath.Join(snapshotArchDir, "include") configsDir := filepath.Join(snapshotArchDir, "configs") @@ -337,7 +230,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { // Common properties among snapshots. prop.ModuleName = ctx.ModuleName(m) - if c.supportsVndkExt && m.IsVndkExt() { + if supportsVndkExt(s.Image) && m.IsVndkExt() { // vndk exts are installed to /vendor/lib(64)?/vndk(-sp)? if m.IsVndkSp() { prop.RelativeInstallPath = "vndk-sp" @@ -469,10 +362,10 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { } moduleDir := ctx.ModuleDir(module) - inProprietaryPath := c.image.isProprietaryPath(moduleDir, ctx.DeviceConfig()) + inProprietaryPath := s.Image.IsProprietaryPath(moduleDir, ctx.DeviceConfig()) apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) - if c.image.excludeFromSnapshot(m) { + if s.Image.ExcludeFromSnapshot(m) { if inProprietaryPath { // Error: exclude_from_vendor_snapshot applies // to framework-path modules only. @@ -481,7 +374,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { } } - if !isSnapshotAware(ctx.DeviceConfig(), m, inProprietaryPath, apexInfo, c.image) { + if !isSnapshotAware(ctx.DeviceConfig(), m, inProprietaryPath, apexInfo, s.Image) { return } @@ -489,8 +382,8 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { // list, we will still include the module as if it was a fake module. // The reason is that soong needs all the dependencies to be present, even // if they are not using during the build. - installAsFake := c.fake - if c.image.excludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) { + installAsFake := s.Fake + if s.Image.ExcludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) { installAsFake = true } @@ -514,47 +407,12 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { // install all headers after removing duplicates for _, header := range android.FirstUniquePaths(headers) { - snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), c.fake)) + snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), s.Fake)) } - // All artifacts are ready. Sort them to normalize ninja and then zip. - sort.Slice(snapshotOutputs, func(i, j int) bool { - return snapshotOutputs[i].String() < snapshotOutputs[j].String() - }) - - zipPath := android.PathForOutput( - ctx, - snapshotDir, - c.name+"-"+ctx.Config().DeviceName()+".zip") - zipRule := android.NewRuleBuilder(pctx, ctx) - - // filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr - snapshotOutputList := android.PathForOutput( - ctx, - snapshotDir, - c.name+"-"+ctx.Config().DeviceName()+"_list") - rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp") - zipRule.Command(). - Text("tr"). - FlagWithArg("-d ", "\\'"). - FlagWithRspFileInputList("< ", rspFile, snapshotOutputs). - FlagWithOutput("> ", snapshotOutputList) - - zipRule.Temporary(snapshotOutputList) - - zipRule.Command(). - BuiltTool("soong_zip"). - FlagWithOutput("-o ", zipPath). - FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()). - FlagWithInput("-l ", snapshotOutputList) - - zipRule.Build(zipPath.String(), c.name+" snapshot "+zipPath.String()) - zipRule.DeleteTemporaryFiles() - c.snapshotZipFile = android.OptionalPathForPath(zipPath) + return snapshotOutputs } -func (c *snapshotSingleton) MakeVars(ctx android.MakeVarsContext) { - ctx.Strict( - c.makeVar, - c.snapshotZipFile.String()) +func init() { + snapshot.RegisterSnapshotAction(ccSnapshotAction) } diff --git a/rust/Android.bp b/rust/Android.bp index 11069d143..221014e5c 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -11,6 +11,7 @@ bootstrap_go_package { "soong-bloaty", "soong-cc", "soong-rust-config", + "soong-snapshot", ], srcs: [ "androidmk.go", diff --git a/rust/library.go b/rust/library.go index 747a29d72..d5ab1a477 100644 --- a/rust/library.go +++ b/rust/library.go @@ -21,6 +21,7 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/snapshot" ) var ( @@ -639,7 +640,7 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { variation := v.(*Module).ModuleBase.ImageVariation().Variation if strings.HasPrefix(variation, cc.VendorVariationPrefix) && m.HasVendorVariant() && - !cc.IsVendorProprietaryModule(mctx) && + !snapshot.IsVendorProprietaryModule(mctx) && strings.TrimPrefix(variation, cc.VendorVariationPrefix) == mctx.DeviceConfig().VndkVersion() { // cc.MutateImage runs before LibraryMutator, so vendor variations which are meant for rlibs only are diff --git a/rust/snapshot_prebuilt.go b/rust/snapshot_prebuilt.go index 2f549738c..79eaab382 100644 --- a/rust/snapshot_prebuilt.go +++ b/rust/snapshot_prebuilt.go @@ -17,6 +17,7 @@ package rust import ( "android/soong/android" "android/soong/cc" + "github.com/google/blueprint/proptools" ) diff --git a/snapshot/Android.bp b/snapshot/Android.bp new file mode 100644 index 000000000..c7e9d7e10 --- /dev/null +++ b/snapshot/Android.bp @@ -0,0 +1,21 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-snapshot", + pkgPath: "android/soong/snapshot", + deps: [ + "blueprint", + "blueprint-pathtools", + "soong", + "soong-android", + ], + srcs: [ + "recovery_snapshot.go", + "snapshot.go", + "snapshot_base.go", + "vendor_snapshot.go", + ], + pluginFor: ["soong_build"], +} diff --git a/snapshot/recovery_snapshot.go b/snapshot/recovery_snapshot.go new file mode 100644 index 000000000..9b3919c34 --- /dev/null +++ b/snapshot/recovery_snapshot.go @@ -0,0 +1,130 @@ +// Copyright 2021 The Android Open Source Project +// +// 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 snapshot + +import "android/soong/android" + +// Interface for modules which can be captured in the recovery snapshot. +type RecoverySnapshotModuleInterface interface { + SnapshotModuleInterfaceBase + InRecovery() bool + ExcludeFromRecoverySnapshot() bool +} + +var recoverySnapshotSingleton = SnapshotSingleton{ + "recovery", // name + "SOONG_RECOVERY_SNAPSHOT_ZIP", // makeVar + android.OptionalPath{}, // snapshotZipFile + RecoverySnapshotImageSingleton, // Image + false, // Fake +} + +func RecoverySnapshotSingleton() android.Singleton { + return &recoverySnapshotSingleton +} + +// Determine if a dir under source tree is an SoC-owned proprietary directory based +// on recovery snapshot configuration +// Examples: device/, vendor/ +func isRecoveryProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return RecoverySnapshotSingleton().(*SnapshotSingleton).Image.IsProprietaryPath(dir, deviceConfig) +} + +func IsRecoveryProprietaryModule(ctx android.BaseModuleContext) bool { + + // Any module in a recovery proprietary path is a recovery proprietary + // module. + if isRecoveryProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) { + return true + } + + // However if the module is not in a recovery proprietary path, it may + // still be a recovery proprietary module. This happens for cc modules + // that are excluded from the recovery snapshot, and it means that the + // vendor has assumed control of the framework-provided module. + + if c, ok := ctx.Module().(RecoverySnapshotModuleInterface); ok { + if c.ExcludeFromRecoverySnapshot() { + return true + } + } + + return false +} + +var RecoverySnapshotImageName = "recovery" + +type RecoverySnapshotImage struct{} + +func (RecoverySnapshotImage) Init(ctx android.RegistrationContext) { + ctx.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton) +} + +func (RecoverySnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool { + // RECOVERY_SNAPSHOT_VERSION must be set to 'current' in order to generate a + // snapshot. + return ctx.DeviceConfig().RecoverySnapshotVersion() == "current" +} + +func (RecoverySnapshotImage) InImage(m SnapshotModuleInterfaceBase) func() bool { + r, ok := m.(RecoverySnapshotModuleInterface) + + if !ok { + // This module does not support recovery snapshot + return func() bool { return false } + } + return r.InRecovery +} + +func (RecoverySnapshotImage) IsProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return isDirectoryExcluded(dir, deviceConfig.RecoverySnapshotDirsExcludedMap(), deviceConfig.RecoverySnapshotDirsIncludedMap()) +} + +func (RecoverySnapshotImage) ExcludeFromSnapshot(m SnapshotModuleInterfaceBase) bool { + r, ok := m.(RecoverySnapshotModuleInterface) + + if !ok { + // This module does not support recovery snapshot + return true + } + return r.ExcludeFromRecoverySnapshot() +} + +func (RecoverySnapshotImage) IsUsingSnapshot(cfg android.DeviceConfig) bool { + recoverySnapshotVersion := cfg.RecoverySnapshotVersion() + return recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" +} + +func (RecoverySnapshotImage) TargetSnapshotVersion(cfg android.DeviceConfig) string { + return cfg.RecoverySnapshotVersion() +} + +func (RecoverySnapshotImage) ExcludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool { + // If we're using full snapshot, not directed snapshot, capture every module + if !cfg.DirectedRecoverySnapshot() { + return false + } + // Else, checks if name is in RECOVERY_SNAPSHOT_MODULES. + return !cfg.RecoverySnapshotModules()[name] +} + +func (RecoverySnapshotImage) ImageName() string { + return RecoverySnapshotImageName +} + +var RecoverySnapshotImageSingleton RecoverySnapshotImage + +func init() { + RecoverySnapshotImageSingleton.Init(android.InitRegistrationContext) +} diff --git a/snapshot/snapshot.go b/snapshot/snapshot.go new file mode 100644 index 000000000..294f8b611 --- /dev/null +++ b/snapshot/snapshot.go @@ -0,0 +1,122 @@ +// Copyright 2021 The Android Open Source Project +// +// 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 snapshot + +import ( + "path/filepath" + "sort" + + "android/soong/android" +) + +// This file contains singletons to capture snapshots. This singleton will generate snapshot of each target +// image, and capturing snapshot module will be delegated to each module which implements GenerateSnapshotAction +// function and register with RegisterSnapshotAction. + +var pctx = android.NewPackageContext("android/soong/snapshot") + +type SnapshotSingleton struct { + // Name, e.g., "vendor", "recovery", "ramdisk". + name string + + // Make variable that points to the snapshot file, e.g., + // "SOONG_RECOVERY_SNAPSHOT_ZIP". + makeVar string + + // Path to the snapshot zip file. + snapshotZipFile android.OptionalPath + + // Implementation of the image interface specific to the image + // associated with this snapshot (e.g., specific to the vendor image, + // recovery image, etc.). + Image SnapshotImage + + // Whether this singleton is for fake snapshot or not. + // Fake snapshot is a snapshot whose prebuilt binaries and headers are empty. + // It is much faster to generate, and can be used to inspect dependencies. + Fake bool +} + +// Interface of function to capture snapshot from each module +type GenerateSnapshotAction func(snapshot SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths + +var snapshotActionList []GenerateSnapshotAction + +// Register GenerateSnapshotAction function so it can be called while generating snapshot +func RegisterSnapshotAction(x GenerateSnapshotAction) { + snapshotActionList = append(snapshotActionList, x) +} + +func (c *SnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { + if !c.Image.shouldGenerateSnapshot(ctx) { + return + } + + var snapshotOutputs android.Paths + + // Snapshot zipped artifacts will be captured under {SNAPSHOT_ARCH} directory + + snapshotDir := c.name + "-snapshot" + if c.Fake { + // If this is a fake snapshot singleton, place all files under fake/ subdirectory to avoid + // collision with real snapshot files + snapshotDir = filepath.Join("fake", snapshotDir) + } + snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch()) + + for _, f := range snapshotActionList { + snapshotOutputs = append(snapshotOutputs, f(*c, ctx, snapshotArchDir)...) + } + + // All artifacts are ready. Sort them to normalize ninja and then zip. + sort.Slice(snapshotOutputs, func(i, j int) bool { + return snapshotOutputs[i].String() < snapshotOutputs[j].String() + }) + + zipPath := android.PathForOutput( + ctx, + snapshotDir, + c.name+"-"+ctx.Config().DeviceName()+".zip") + zipRule := android.NewRuleBuilder(pctx, ctx) + + // filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr + snapshotOutputList := android.PathForOutput( + ctx, + snapshotDir, + c.name+"-"+ctx.Config().DeviceName()+"_list") + rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp") + zipRule.Command(). + Text("tr"). + FlagWithArg("-d ", "\\'"). + FlagWithRspFileInputList("< ", rspFile, snapshotOutputs). + FlagWithOutput("> ", snapshotOutputList) + + zipRule.Temporary(snapshotOutputList) + + zipRule.Command(). + BuiltTool("soong_zip"). + FlagWithOutput("-o ", zipPath). + FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()). + FlagWithInput("-l ", snapshotOutputList) + + zipRule.Build(zipPath.String(), c.name+" snapshot "+zipPath.String()) + zipRule.DeleteTemporaryFiles() + c.snapshotZipFile = android.OptionalPathForPath(zipPath) +} + +func (c *SnapshotSingleton) MakeVars(ctx android.MakeVarsContext) { + ctx.Strict( + c.makeVar, + c.snapshotZipFile.String()) +} diff --git a/snapshot/snapshot_base.go b/snapshot/snapshot_base.go new file mode 100644 index 000000000..de93f3eb0 --- /dev/null +++ b/snapshot/snapshot_base.go @@ -0,0 +1,104 @@ +// Copyright 2021 The Android Open Source Project +// +// 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 snapshot + +import ( + "android/soong/android" + "path/filepath" +) + +// Interface for modules which can be captured in the snapshot. +type SnapshotModuleInterfaceBase interface{} + +// Defines the specifics of different images to which the snapshot process is applicable, e.g., +// vendor, recovery, ramdisk. +type SnapshotImage interface { + // Returns true if a snapshot should be generated for this image. + shouldGenerateSnapshot(ctx android.SingletonContext) bool + + // Function that returns true if the module is included in this image. + // Using a function return instead of a value to prevent early + // evalution of a function that may be not be defined. + InImage(m SnapshotModuleInterfaceBase) func() bool + + // Returns true if a dir under source tree is an SoC-owned proprietary + // directory, such as device/, vendor/, etc. + // + // For a given snapshot (e.g., vendor, recovery, etc.) if + // isProprietaryPath(dir, deviceConfig) returns true, then the module in dir + // will be built from sources. + IsProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool + + // Whether a given module has been explicitly excluded from the + // snapshot, e.g., using the exclude_from_vendor_snapshot or + // exclude_from_recovery_snapshot properties. + ExcludeFromSnapshot(m SnapshotModuleInterfaceBase) bool + + // Returns true if the build is using a snapshot for this image. + IsUsingSnapshot(cfg android.DeviceConfig) bool + + // Returns a version of which the snapshot should be used in this target. + // This will only be meaningful when isUsingSnapshot is true. + TargetSnapshotVersion(cfg android.DeviceConfig) string + + // Whether to exclude a given module from the directed snapshot or not. + // If the makefile variable DIRECTED_{IMAGE}_SNAPSHOT is true, directed snapshot is turned on, + // and only modules listed in {IMAGE}_SNAPSHOT_MODULES will be captured. + ExcludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool + + // Returns target image name + ImageName() string +} + +type directoryMap map[string]bool + +var ( + // Modules under following directories are ignored. They are OEM's and vendor's + // proprietary modules(device/, kernel/, vendor/, and hardware/). + defaultDirectoryExcludedMap = directoryMap{ + "device": true, + "hardware": true, + "kernel": true, + "vendor": true, + } + + // Modules under following directories are included as they are in AOSP, + // although hardware/ and kernel/ are normally for vendor's own. + defaultDirectoryIncludedMap = directoryMap{ + "kernel/configs": true, + "kernel/prebuilts": true, + "kernel/tests": true, + "hardware/interfaces": true, + "hardware/libhardware": true, + "hardware/libhardware_legacy": true, + "hardware/ril": true, + } +) + +func isDirectoryExcluded(dir string, excludedMap directoryMap, includedMap directoryMap) bool { + if dir == "." || dir == "/" { + return false + } + if includedMap[dir] { + return false + } else if excludedMap[dir] { + return true + } else if defaultDirectoryIncludedMap[dir] { + return false + } else if defaultDirectoryExcludedMap[dir] { + return true + } else { + return isDirectoryExcluded(filepath.Dir(dir), excludedMap, includedMap) + } +} diff --git a/snapshot/vendor_snapshot.go b/snapshot/vendor_snapshot.go new file mode 100644 index 000000000..9bd26c201 --- /dev/null +++ b/snapshot/vendor_snapshot.go @@ -0,0 +1,147 @@ +// Copyright 2021 The Android Open Source Project +// +// 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 snapshot + +import "android/soong/android" + +// Interface for modules which can be captured in the vendor snapshot. +type VendorSnapshotModuleInterface interface { + SnapshotModuleInterfaceBase + InVendor() bool + ExcludeFromVendorSnapshot() bool +} + +var vendorSnapshotSingleton = SnapshotSingleton{ + "vendor", // name + "SOONG_VENDOR_SNAPSHOT_ZIP", // makeVar + android.OptionalPath{}, // snapshotZipFile + VendorSnapshotImageSingleton, // Image + false, // Fake +} + +var vendorFakeSnapshotSingleton = SnapshotSingleton{ + "vendor", // name + "SOONG_VENDOR_FAKE_SNAPSHOT_ZIP", // makeVar + android.OptionalPath{}, // snapshotZipFile + VendorSnapshotImageSingleton, // Image + true, // Fake +} + +func VendorSnapshotSingleton() android.Singleton { + return &vendorSnapshotSingleton +} + +func VendorFakeSnapshotSingleton() android.Singleton { + return &vendorFakeSnapshotSingleton +} + +// Determine if a dir under source tree is an SoC-owned proprietary directory based +// on vendor snapshot configuration +// Examples: device/, vendor/ +func isVendorProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return VendorSnapshotSingleton().(*SnapshotSingleton).Image.IsProprietaryPath(dir, deviceConfig) +} + +func IsVendorProprietaryModule(ctx android.BaseModuleContext) bool { + // Any module in a vendor proprietary path is a vendor proprietary + // module. + if isVendorProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) { + return true + } + + // However if the module is not in a vendor proprietary path, it may + // still be a vendor proprietary module. This happens for cc modules + // that are excluded from the vendor snapshot, and it means that the + // vendor has assumed control of the framework-provided module. + if c, ok := ctx.Module().(VendorSnapshotModuleInterface); ok { + if c.ExcludeFromVendorSnapshot() { + return true + } + } + + return false +} + +var VendorSnapshotImageName = "vendor" + +type VendorSnapshotImage struct{} + +func (VendorSnapshotImage) Init(ctx android.RegistrationContext) { + ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton) + ctx.RegisterSingletonType("vendor-fake-snapshot", VendorFakeSnapshotSingleton) +} + +func (VendorSnapshotImage) RegisterAdditionalModule(ctx android.RegistrationContext, name string, factory android.ModuleFactory) { + ctx.RegisterModuleType(name, factory) +} + +func (VendorSnapshotImage) shouldGenerateSnapshot(ctx android.SingletonContext) bool { + // BOARD_VNDK_VERSION must be set to 'current' in order to generate a snapshot. + return ctx.DeviceConfig().VndkVersion() == "current" +} + +func (VendorSnapshotImage) InImage(m SnapshotModuleInterfaceBase) func() bool { + v, ok := m.(VendorSnapshotModuleInterface) + + if !ok { + // This module does not support Vendor snapshot + return func() bool { return false } + } + + return v.InVendor +} + +func (VendorSnapshotImage) IsProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool { + return isDirectoryExcluded(dir, deviceConfig.VendorSnapshotDirsExcludedMap(), deviceConfig.VendorSnapshotDirsIncludedMap()) +} + +func (VendorSnapshotImage) ExcludeFromSnapshot(m SnapshotModuleInterfaceBase) bool { + v, ok := m.(VendorSnapshotModuleInterface) + + if !ok { + // This module does not support Vendor snapshot + return true + } + + return v.ExcludeFromVendorSnapshot() +} + +func (VendorSnapshotImage) IsUsingSnapshot(cfg android.DeviceConfig) bool { + vndkVersion := cfg.VndkVersion() + return vndkVersion != "current" && vndkVersion != "" +} + +func (VendorSnapshotImage) TargetSnapshotVersion(cfg android.DeviceConfig) string { + return cfg.VndkVersion() +} + +// returns true iff a given module SHOULD BE EXCLUDED, false if included +func (VendorSnapshotImage) ExcludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool { + // If we're using full snapshot, not directed snapshot, capture every module + if !cfg.DirectedVendorSnapshot() { + return false + } + // Else, checks if name is in VENDOR_SNAPSHOT_MODULES. + return !cfg.VendorSnapshotModules()[name] +} + +func (VendorSnapshotImage) ImageName() string { + return VendorSnapshotImageName +} + +var VendorSnapshotImageSingleton VendorSnapshotImage + +func init() { + VendorSnapshotImageSingleton.Init(android.InitRegistrationContext) +}