diff --git a/android/module.go b/android/module.go index 11f63bd49..b40310b85 100644 --- a/android/module.go +++ b/android/module.go @@ -413,6 +413,7 @@ type ModuleContext interface { InstallInDebugRamdisk() bool InstallInRecovery() bool InstallInRoot() bool + InstallInVendor() bool InstallBypassMake() bool InstallForceOS() (*OsType, *ArchType) @@ -471,6 +472,7 @@ type Module interface { InstallInDebugRamdisk() bool InstallInRecovery() bool InstallInRoot() bool + InstallInVendor() bool InstallBypassMake() bool InstallForceOS() (*OsType, *ArchType) HideFromMake() @@ -1579,6 +1581,10 @@ func (m *ModuleBase) InstallInRecovery() bool { return Bool(m.commonProperties.Recovery) } +func (m *ModuleBase) InstallInVendor() bool { + return Bool(m.commonProperties.Vendor) +} + func (m *ModuleBase) InstallInRoot() bool { return false } @@ -2645,6 +2651,10 @@ func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) { return m.module.InstallForceOS() } +func (m *moduleContext) InstallInVendor() bool { + return m.module.InstallInVendor() +} + func (m *moduleContext) skipInstall() bool { if m.module.base().commonProperties.SkipInstall { return true diff --git a/cc/Android.bp b/cc/Android.bp index 4b750ff25..164d32b12 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/util.go b/cc/util.go index 1220d8432..9bba87676 100644 --- a/cc/util.go +++ b/cc/util.go @@ -21,6 +21,7 @@ import ( "strings" "android/soong/android" + "android/soong/snapshot" ) // Efficiently converts a list of include directories to a single string @@ -126,20 +127,6 @@ func makeSymlinkCmd(linkDirOnDevice string, linkName string, target string) stri "ln -sf " + target + " " + filepath.Join(dir, linkName) } -func copyFileRule(ctx android.SingletonContext, path android.Path, out string) android.OutputPath { - outPath := android.PathForOutput(ctx, out) - ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Input: path, - Output: outPath, - Description: "copy " + path.String() + " -> " + out, - Args: map[string]string{ - "cpFlags": "-f -L", - }, - }) - return outPath -} - func combineNoticesRule(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath { outPath := android.PathForOutput(ctx, out) ctx.Build(pctx, android.BuildParams{ @@ -151,12 +138,6 @@ func combineNoticesRule(ctx android.SingletonContext, paths android.Paths, out s return outPath } -func writeStringToFileRule(ctx android.SingletonContext, content, out string) android.OutputPath { - outPath := android.PathForOutput(ctx, out) - android.WriteFileRule(ctx, outPath, content) - return outPath -} - // Dump a map to a list file as: // // {key1} {value1} @@ -172,5 +153,5 @@ func installMapListFileRule(ctx android.SingletonContext, m map[string]string, p txtBuilder.WriteString(" ") txtBuilder.WriteString(m[k]) } - return writeStringToFileRule(ctx, txtBuilder.String(), path) + return snapshot.WriteStringToFileRule(ctx, txtBuilder.String(), path) } diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index 003b7c98b..ba4d79fcf 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") @@ -317,9 +210,9 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { if fake { // All prebuilt binaries and headers are installed by copyFile function. This makes a fake // snapshot just touch prebuilts and headers, rather than installing real files. - return writeStringToFileRule(ctx, "", out) + return snapshot.WriteStringToFileRule(ctx, "", out) } else { - return copyFileRule(ctx, path, out) + return snapshot.CopyFileRule(pctx, ctx, path, out) } } @@ -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" @@ -457,7 +350,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { ctx.Errorf("json marshal to %q failed: %#v", propOut, err) return nil } - ret = append(ret, writeStringToFileRule(ctx, string(j), propOut)) + ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut)) return ret } @@ -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/cc/vndk.go b/cc/vndk.go index 499d4282c..1ae79de05 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -25,6 +25,7 @@ import ( "android/soong/android" "android/soong/cc/config" "android/soong/etc" + "android/soong/snapshot" "github.com/google/blueprint" ) @@ -698,7 +699,7 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex libPath := m.outputFile.Path() snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base()) - ret = append(ret, copyFileRule(ctx, libPath, snapshotLibOut)) + ret = append(ret, snapshot.CopyFileRule(pctx, ctx, libPath, snapshotLibOut)) if ctx.Config().VndkSnapshotBuildArtifacts() { prop := struct { @@ -720,7 +721,7 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex ctx.Errorf("json marshal to %q failed: %#v", propOut, err) return nil, false } - ret = append(ret, writeStringToFileRule(ctx, string(j), propOut)) + ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut)) } return ret, true } @@ -778,8 +779,8 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex // install all headers after removing duplicates for _, header := range android.FirstUniquePaths(headers) { - snapshotOutputs = append(snapshotOutputs, copyFileRule( - ctx, header, filepath.Join(includeDir, header.String()))) + snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule( + pctx, ctx, header, filepath.Join(includeDir, header.String()))) } // install *.libraries.txt except vndkcorevariant.libraries.txt @@ -788,8 +789,8 @@ func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContex if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt { return } - snapshotOutputs = append(snapshotOutputs, copyFileRule( - ctx, m.OutputFile(), filepath.Join(configsDir, m.Name()))) + snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule( + pctx, ctx, m.OutputFile(), filepath.Join(configsDir, m.Name()))) }) /* diff --git a/etc/Android.bp b/etc/Android.bp index cab7389b6..06a2fa15d 100644 --- a/etc/Android.bp +++ b/etc/Android.bp @@ -9,6 +9,7 @@ bootstrap_go_package { "blueprint", "soong", "soong-android", + "soong-snapshot", ], srcs: [ "prebuilt_etc.go", diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 4dd383d77..4107916a7 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -28,12 +28,15 @@ package etc // various `prebuilt_*` mutators. import ( + "encoding/json" "fmt" + "path/filepath" "strings" "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/snapshot" ) var pctx = android.NewPackageContext("android/soong/etc") @@ -43,6 +46,7 @@ var pctx = android.NewPackageContext("android/soong/etc") func init() { pctx.Import("android/soong/android") RegisterPrebuiltEtcBuildComponents(android.InitRegistrationContext) + snapshot.RegisterSnapshotAction(generatePrebuiltSnapshot) } func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) { @@ -128,6 +132,9 @@ type PrebuiltEtc struct { android.ModuleBase android.DefaultableModuleBase + snapshot.VendorSnapshotModuleInterface + snapshot.RecoverySnapshotModuleInterface + properties prebuiltEtcProperties subdirProperties prebuiltSubdirProperties @@ -183,7 +190,7 @@ func (p *PrebuiltEtc) InstallInDebugRamdisk() bool { return p.inDebugRamdisk() } -func (p *PrebuiltEtc) inRecovery() bool { +func (p *PrebuiltEtc) InRecovery() bool { return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery() } @@ -192,7 +199,7 @@ func (p *PrebuiltEtc) onlyInRecovery() bool { } func (p *PrebuiltEtc) InstallInRecovery() bool { - return p.inRecovery() + return p.InRecovery() } var _ android.ImageInterface = (*PrebuiltEtc)(nil) @@ -271,6 +278,18 @@ func (p *PrebuiltEtc) Installable() bool { return p.properties.Installable == nil || proptools.Bool(p.properties.Installable) } +func (p *PrebuiltEtc) InVendor() bool { + return p.ModuleBase.InstallInVendor() +} + +func (p *PrebuiltEtc) ExcludeFromVendorSnapshot() bool { + return false +} + +func (p *PrebuiltEtc) ExcludeFromRecoverySnapshot() bool { + return false +} + func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { if p.properties.Src == nil { ctx.PropertyErrorf("src", "missing prebuilt source file") @@ -344,7 +363,7 @@ func (p *PrebuiltEtc) AndroidMkEntries() []android.AndroidMkEntries { if p.inDebugRamdisk() && !p.onlyInDebugRamdisk() { nameSuffix = ".debug_ramdisk" } - if p.inRecovery() && !p.onlyInRecovery() { + if p.InRecovery() && !p.onlyInRecovery() { nameSuffix = ".recovery" } return []android.AndroidMkEntries{android.AndroidMkEntries{ @@ -494,3 +513,137 @@ func PrebuiltRFSAFactory() android.Module { android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) return module } + +// Flags to be included in the snapshot +type snapshotJsonFlags struct { + ModuleName string `json:",omitempty"` + Filename string `json:",omitempty"` + RelativeInstallPath string `json:",omitempty"` +} + +// Copy file into the snapshot +func copyFile(ctx android.SingletonContext, path android.Path, out string, fake bool) android.OutputPath { + if fake { + // Create empty file instead for the fake snapshot + return snapshot.WriteStringToFileRule(ctx, "", out) + } else { + return snapshot.CopyFileRule(pctx, ctx, path, out) + } +} + +// Check if the module is target of the snapshot +func isSnapshotAware(ctx android.SingletonContext, m *PrebuiltEtc, image snapshot.SnapshotImage) bool { + if !m.Enabled() { + return false + } + + // Skip if the module is not included in the image + if !image.InImage(m)() { + return false + } + + // When android/prebuilt.go selects between source and prebuilt, it sets + // HideFromMake on the other one to avoid duplicate install rules in make. + if m.IsHideFromMake() { + return false + } + + // There are some prebuilt_etc module with multiple definition of same name. + // Check if the target would be included from the build + if !m.ExportedToMake() { + return false + } + + // Skip if the module is in the predefined path list to skip + if image.IsProprietaryPath(ctx.ModuleDir(m), ctx.DeviceConfig()) { + return false + } + + // Skip if the module should be excluded + if image.ExcludeFromSnapshot(m) || image.ExcludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) { + return false + } + + // Skip from other exceptional cases + if m.Target().Os.Class != android.Device { + return false + } + if m.Target().NativeBridge == android.NativeBridgeEnabled { + return false + } + + return true +} + +func generatePrebuiltSnapshot(s snapshot.SnapshotSingleton, ctx android.SingletonContext, snapshotArchDir string) android.Paths { + /* + Snapshot zipped artifacts directory structure for etc modules: + {SNAPSHOT_ARCH}/ + arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/ + etc/ + (prebuilt etc files) + arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/ + etc/ + (prebuilt etc files) + NOTICE_FILES/ + (notice files) + */ + var snapshotOutputs android.Paths + noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES") + installedNotices := make(map[string]bool) + + ctx.VisitAllModules(func(module android.Module) { + m, ok := module.(*PrebuiltEtc) + if !ok { + return + } + + if !isSnapshotAware(ctx, m, s.Image) { + return + } + + targetArch := "arch-" + m.Target().Arch.ArchType.String() + + snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "etc", m.BaseModuleName()) + snapshotOutputs = append(snapshotOutputs, copyFile(ctx, m.OutputFile(), snapshotLibOut, s.Fake)) + + prop := snapshotJsonFlags{} + propOut := snapshotLibOut + ".json" + prop.ModuleName = m.BaseModuleName() + if m.subdirProperties.Relative_install_path != nil { + prop.RelativeInstallPath = *m.subdirProperties.Relative_install_path + } + + if m.properties.Filename != nil { + prop.Filename = *m.properties.Filename + } + + j, err := json.Marshal(prop) + if err != nil { + ctx.Errorf("json marshal to %q failed: %#v", propOut, err) + return + } + snapshotOutputs = append(snapshotOutputs, snapshot.WriteStringToFileRule(ctx, string(j), propOut)) + + if len(m.EffectiveLicenseFiles()) > 0 { + noticeName := ctx.ModuleName(m) + ".txt" + noticeOut := filepath.Join(noticeDir, noticeName) + // skip already copied notice file + if !installedNotices[noticeOut] { + installedNotices[noticeOut] = true + + noticeOutPath := android.PathForOutput(ctx, noticeOut) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cat, + Inputs: m.EffectiveLicenseFiles(), + Output: noticeOutPath, + Description: "combine notices for " + noticeOut, + }) + snapshotOutputs = append(snapshotOutputs, noticeOutPath) + } + } + + }) + + return snapshotOutputs +} diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index 354f6bb6e..0c5cfe4f4 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -15,11 +15,15 @@ package etc import ( + "fmt" "os" "path/filepath" "testing" + "github.com/google/blueprint/proptools" + "android/soong/android" + "android/soong/snapshot" ) func TestMain(m *testing.M) { @@ -36,6 +40,18 @@ var prepareForPrebuiltEtcTest = android.GroupFixturePreparers( }), ) +var prepareForPrebuiltEtcSnapshotTest = android.GroupFixturePreparers( + prepareForPrebuiltEtcTest, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + snapshot.VendorSnapshotImageSingleton.Init(ctx) + snapshot.RecoverySnapshotImageSingleton.Init(ctx) + }), + android.FixtureModifyConfig(func(config android.Config) { + config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current") + config.TestProductVariables.RecoverySnapshotVersion = proptools.StringPtr("current") + }), +) + func TestPrebuiltEtcVariants(t *testing.T) { result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` prebuilt_etc { @@ -346,3 +362,110 @@ func TestPrebuiltRFSADirPath(t *testing.T) { }) } } + +func checkIfSnapshotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) { + checkIfSnapshotExistAsExpected(t, result, image, moduleName, true) +} + +func checkIfSnapshotNotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) { + checkIfSnapshotExistAsExpected(t, result, image, moduleName, false) +} + +func checkIfSnapshotExistAsExpected(t *testing.T, result *android.TestResult, image string, moduleName string, expectToExist bool) { + snapshotSingleton := result.SingletonForTests(image + "-snapshot") + archType := "arm64" + archVariant := "armv8-a" + archDir := fmt.Sprintf("arch-%s", archType) + + snapshotDir := fmt.Sprintf("%s-snapshot", image) + snapshotVariantPath := filepath.Join(snapshotDir, archType) + outputDir := filepath.Join(snapshotVariantPath, archDir, "etc") + imageVariant := "" + if image == "recovery" { + imageVariant = "recovery_" + } + mod := result.ModuleForTests(moduleName, fmt.Sprintf("android_%s%s_%s", imageVariant, archType, archVariant)) + outputFiles := mod.OutputFiles(t, "") + if len(outputFiles) != 1 { + t.Errorf("%q must have single output\n", moduleName) + return + } + snapshotPath := filepath.Join(outputDir, moduleName) + + if expectToExist { + out := snapshotSingleton.Output(snapshotPath) + + if out.Input.String() != outputFiles[0].String() { + t.Errorf("The input of snapshot %q must be %q, but %q", "prebuilt_vendor", out.Input.String(), outputFiles[0]) + } + + snapshotJsonPath := snapshotPath + ".json" + + if snapshotSingleton.MaybeOutput(snapshotJsonPath).Rule == nil { + t.Errorf("%q expected but not found", snapshotJsonPath) + } + } else { + out := snapshotSingleton.MaybeOutput(snapshotPath) + if out.Rule != nil { + t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0]) + } + } +} + +func TestPrebuiltTakeSnapshot(t *testing.T) { + var testBp = ` + prebuilt_etc { + name: "prebuilt_vendor", + src: "foo.conf", + vendor: true, + } + + prebuilt_etc { + name: "prebuilt_vendor_indirect", + src: "foo.conf", + vendor: true, + } + + prebuilt_etc { + name: "prebuilt_recovery", + src: "bar.conf", + recovery: true, + } + + prebuilt_etc { + name: "prebuilt_recovery_indirect", + src: "bar.conf", + recovery: true, + } + ` + + t.Run("prebuilt: vendor and recovery snapshot", func(t *testing.T) { + result := prepareForPrebuiltEtcSnapshotTest.RunTestWithBp(t, testBp) + + checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor") + checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor_indirect") + checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery") + checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery_indirect") + }) + + t.Run("prebuilt: directed snapshot", func(t *testing.T) { + prepareForPrebuiltEtcDirectedSnapshotTest := android.GroupFixturePreparers( + prepareForPrebuiltEtcSnapshotTest, + android.FixtureModifyConfig(func(config android.Config) { + config.TestProductVariables.DirectedVendorSnapshot = true + config.TestProductVariables.VendorSnapshotModules = make(map[string]bool) + config.TestProductVariables.VendorSnapshotModules["prebuilt_vendor"] = true + config.TestProductVariables.DirectedRecoverySnapshot = true + config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool) + config.TestProductVariables.RecoverySnapshotModules["prebuilt_recovery"] = true + }), + ) + + result := prepareForPrebuiltEtcDirectedSnapshotTest.RunTestWithBp(t, testBp) + + checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor") + checkIfSnapshotNotTaken(t, result, "vendor", "prebuilt_vendor_indirect") + checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery") + checkIfSnapshotNotTaken(t, result, "recovery", "prebuilt_recovery_indirect") + }) +} 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 5a36bd13f..8c10e298b 100644 --- a/rust/library.go +++ b/rust/library.go @@ -21,6 +21,7 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/snapshot" ) var ( @@ -645,7 +646,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..f17ac532a --- /dev/null +++ b/snapshot/Android.bp @@ -0,0 +1,22 @@ +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", + "util.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/util.go b/snapshot/util.go new file mode 100644 index 000000000..2297dfc2b --- /dev/null +++ b/snapshot/util.go @@ -0,0 +1,36 @@ +// 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" + +func WriteStringToFileRule(ctx android.SingletonContext, content, out string) android.OutputPath { + outPath := android.PathForOutput(ctx, out) + android.WriteFileRule(ctx, outPath, content) + return outPath +} + +func CopyFileRule(pctx android.PackageContext, ctx android.SingletonContext, path android.Path, out string) android.OutputPath { + outPath := android.PathForOutput(ctx, out) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: path, + Output: outPath, + Description: "copy " + path.String() + " -> " + out, + Args: map[string]string{ + "cpFlags": "-f -L", + }, + }) + return outPath +} 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) +}