From 6f843bc4babc367057dcec087cf21bead53b76d7 Mon Sep 17 00:00:00 2001 From: Jose Galmes Date: Fri, 11 Dec 2020 13:36:29 -0800 Subject: [PATCH] Support for recovery snapshot. Bug: 171231437 Test: source build/envsetup.sh Test: ALLOW_MISSING_DEPENDENCIES=true m -j nothing Change-Id: I74636cf7f97e027a229a5ef7c776f2b7a42ead95 --- android/config.go | 4 + android/variable.go | 2 + cc/androidmk.go | 18 +-- cc/cc.go | 82 +++++++--- cc/cc_test.go | 114 ++++++++++++- cc/genrule.go | 10 +- cc/image.go | 26 ++- cc/library.go | 3 +- cc/makevars.go | 1 + cc/snapshot_prebuilt.go | 345 +++++++++++++++++++++++++++++++--------- cc/snapshot_utils.go | 4 + cc/vendor_snapshot.go | 30 +++- 12 files changed, 520 insertions(+), 119 deletions(-) diff --git a/android/config.go b/android/config.go index 89467d8db..6ab798da8 100644 --- a/android/config.go +++ b/android/config.go @@ -1053,6 +1053,10 @@ func (c *deviceConfig) VndkVersion() string { return String(c.config.productVariables.DeviceVndkVersion) } +func (c *deviceConfig) RecoverySnapshotVersion() string { + return String(c.config.productVariables.RecoverySnapshotVersion) +} + func (c *deviceConfig) CurrentApiLevelForVendorModules() string { return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current") } diff --git a/android/variable.go b/android/variable.go index 753ddd7f7..4e9eef5e6 100644 --- a/android/variable.go +++ b/android/variable.go @@ -181,6 +181,8 @@ type productVariables struct { DeviceCurrentApiLevelForVendorModules *string `json:",omitempty"` DeviceSystemSdkVersions []string `json:",omitempty"` + RecoverySnapshotVersion *string `json:",omitempty"` + DeviceSecondaryArch *string `json:",omitempty"` DeviceSecondaryArchVariant *string `json:",omitempty"` DeviceSecondaryCpuVariant *string `json:",omitempty"` diff --git a/cc/androidmk.go b/cc/androidmk.go index 4ada55dd3..040aa0b9f 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -519,9 +519,7 @@ func (c *snapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entrie entries.SubName += ".cfi" } - if c.androidMkVendorSuffix { - entries.SubName += vendorSuffix - } + entries.SubName += c.androidMkSuffix entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { c.libraryDecorator.androidMkWriteExportedFlags(entries) @@ -548,12 +546,7 @@ func (c *snapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entrie func (c *snapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { entries.Class = "EXECUTABLES" - - if c.androidMkVendorSuffix { - entries.SubName = vendorSuffix - } else { - entries.SubName = "" - } + entries.SubName = c.androidMkSuffix entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { entries.AddStrings("LOCAL_MODULE_SYMLINKS", c.Properties.Symlinks...) @@ -562,12 +555,7 @@ func (c *snapshotBinaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries func (c *snapshotObjectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { entries.Class = "STATIC_LIBRARIES" - - if c.androidMkVendorSuffix { - entries.SubName = vendorSuffix - } else { - entries.SubName = "" - } + entries.SubName = c.androidMkSuffix entries.ExtraFooters = append(entries.ExtraFooters, func(w io.Writer, name, prefix, moduleDir string) { diff --git a/cc/cc.go b/cc/cc.go index a023f3f83..991ccc5b2 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -52,6 +52,8 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.BottomUp("sysprop_cc", SyspropMutator).Parallel() ctx.BottomUp("vendor_snapshot", VendorSnapshotMutator).Parallel() ctx.BottomUp("vendor_snapshot_source", VendorSnapshotSourceMutator).Parallel() + ctx.BottomUp("recovery_snapshot", RecoverySnapshotMutator).Parallel() + ctx.BottomUp("recovery_snapshot_source", RecoverySnapshotSourceMutator).Parallel() }) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { @@ -334,10 +336,16 @@ type BaseProperties struct { // Normally Soong uses the directory structure to decide which modules // should be included (framework) or excluded (non-framework) from the - // different snapshots (vendor, recovery, etc.), but these properties - // allow a partner to exclude a module normally thought of as a - // framework module from a snapshot. - Exclude_from_vendor_snapshot *bool + // different snapshots (vendor, recovery, etc.), but this property + // allows a partner to exclude a module normally thought of as a + // framework module from the vendor snapshot. + Exclude_from_vendor_snapshot *bool + + // Normally Soong uses the directory structure to decide which modules + // should be included (framework) or excluded (non-framework) from the + // different snapshots (vendor, recovery, etc.), but this property + // allows a partner to exclude a module normally thought of as a + // framework module from the recovery snapshot. Exclude_from_recovery_snapshot *bool // List of APEXes that this module has private access to for testing purpose. The module @@ -1599,8 +1607,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { // Note: this is still non-installable } - // glob exported headers for snapshot, if BOARD_VNDK_VERSION is current. - if i, ok := c.linker.(snapshotLibraryInterface); ok && ctx.DeviceConfig().VndkVersion() == "current" { + // glob exported headers for snapshot, if BOARD_VNDK_VERSION is current or + // RECOVERY_SNAPSHOT_VERSION is current. + if i, ok := c.linker.(snapshotLibraryInterface); ok { if shouldCollectHeadersForSnapshot(ctx, c, apexInfo) { i.collectHeadersForSnapshot(ctx) } @@ -1842,6 +1851,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { vendorPublicLibraries := vendorPublicLibraries(actx.Config()) vendorSnapshotSharedLibs := vendorSnapshotSharedLibs(actx.Config()) + recoverySnapshotSharedLibs := recoverySnapshotSharedLibs(actx.Config()) rewriteVendorLibs := func(lib string) string { // only modules with BOARD_VNDK_VERSION uses snapshot. @@ -1862,7 +1872,19 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { for _, entry := range list { // strip #version suffix out name, _ := StubsLibNameAndVersion(entry) - if ctx.useSdk() && inList(name, *getNDKKnownLibs(ctx.Config())) { + if c.InRecovery() { + recoverySnapshotVersion := + actx.DeviceConfig().RecoverySnapshotVersion() + if recoverySnapshotVersion == "current" || + recoverySnapshotVersion == "" { + nonvariantLibs = append(nonvariantLibs, name) + } else if snapshot, ok := recoverySnapshotSharedLibs.get( + name, actx.Arch().ArchType); ok { + nonvariantLibs = append(nonvariantLibs, snapshot) + } else { + nonvariantLibs = append(nonvariantLibs, name) + } + } else if ctx.useSdk() && inList(name, *getNDKKnownLibs(ctx.Config())) { variantLibs = append(variantLibs, name+ndkLibrarySuffix) } else if ctx.useVndk() { nonvariantLibs = append(nonvariantLibs, rewriteVendorLibs(entry)) @@ -1907,14 +1929,36 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { return lib } - vendorSnapshotHeaderLibs := vendorSnapshotHeaderLibs(actx.Config()) + snapshotHeaderLibs := vendorSnapshotHeaderLibs(actx.Config()) + snapshotStaticLibs := vendorSnapshotStaticLibs(actx.Config()) + snapshotObjects := vendorSnapshotObjects(actx.Config()) + + if c.InRecovery() { + rewriteSnapshotLibs = func(lib string, snapshotMap *snapshotMap) string { + recoverySnapshotVersion := + actx.DeviceConfig().RecoverySnapshotVersion() + if recoverySnapshotVersion == "current" || + recoverySnapshotVersion == "" { + return lib + } else if snapshot, ok := snapshotMap.get(lib, actx.Arch().ArchType); ok { + return snapshot + } + + return lib + } + + snapshotHeaderLibs = recoverySnapshotHeaderLibs(actx.Config()) + snapshotStaticLibs = recoverySnapshotStaticLibs(actx.Config()) + snapshotObjects = recoverySnapshotObjects(actx.Config()) + } + for _, lib := range deps.HeaderLibs { depTag := libraryDependencyTag{Kind: headerLibraryDependency} if inList(lib, deps.ReexportHeaderLibHeaders) { depTag.reexportFlags = true } - lib = rewriteSnapshotLibs(lib, vendorSnapshotHeaderLibs) + lib = rewriteSnapshotLibs(lib, snapshotHeaderLibs) if c.IsStubs() { actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()), @@ -1930,7 +1974,6 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { // map from sysprop_library to implementation library; it will be used in whole_static_libs, // static_libs, and shared_libs. syspropImplLibraries := syspropImplLibraries(actx.Config()) - vendorSnapshotStaticLibs := vendorSnapshotStaticLibs(actx.Config()) for _, lib := range deps.WholeStaticLibs { depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true, reexportFlags: true} @@ -1938,7 +1981,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { lib = impl } - lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs) + lib = rewriteSnapshotLibs(lib, snapshotStaticLibs) actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, @@ -1958,7 +2001,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { lib = impl } - lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs) + lib = rewriteSnapshotLibs(lib, snapshotStaticLibs) actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, @@ -1972,14 +2015,14 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { depTag := libraryDependencyTag{Kind: staticLibraryDependency, staticUnwinder: true} actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, depTag, rewriteSnapshotLibs(staticUnwinder(actx), vendorSnapshotStaticLibs)) + }, depTag, rewriteSnapshotLibs(staticUnwinder(actx), snapshotStaticLibs)) } for _, lib := range deps.LateStaticLibs { depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency} actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, depTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs)) + }, depTag, rewriteSnapshotLibs(lib, snapshotStaticLibs)) } // shared lib names without the #version suffix @@ -2039,17 +2082,15 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { actx.AddDependency(c, depTag, gen) } - vendorSnapshotObjects := vendorSnapshotObjects(actx.Config()) - crtVariations := GetCrtVariations(ctx, c) actx.AddVariationDependencies(crtVariations, objDepTag, deps.ObjFiles...) if deps.CrtBegin != "" { actx.AddVariationDependencies(crtVariations, CrtBeginDepTag, - rewriteSnapshotLibs(deps.CrtBegin, vendorSnapshotObjects)) + rewriteSnapshotLibs(deps.CrtBegin, snapshotObjects)) } if deps.CrtEnd != "" { actx.AddVariationDependencies(crtVariations, CrtEndDepTag, - rewriteSnapshotLibs(deps.CrtEnd, vendorSnapshotObjects)) + rewriteSnapshotLibs(deps.CrtEnd, snapshotObjects)) } if deps.LinkerFlagsFile != "" { actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile) @@ -2761,6 +2802,7 @@ func baseLibName(depName string) string { func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, depName string) string { vendorSuffixModules := vendorSuffixModules(ctx.Config()) + recoverySuffixModules := recoverySuffixModules(ctx.Config()) vendorPublicLibraries := vendorPublicLibraries(ctx.Config()) libName := baseLibName(depName) @@ -2778,8 +2820,10 @@ func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, return baseName + ".vendor" } - if vendorSuffixModules[baseName] { + if c.inVendor() && vendorSuffixModules[baseName] { return baseName + ".vendor" + } else if c.InRecovery() && recoverySuffixModules[baseName] { + return baseName + ".recovery" } else { return baseName } diff --git a/cc/cc_test.go b/cc/cc_test.go index fe9db37a1..82b39697f 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -1420,6 +1420,13 @@ func assertExcludeFromVendorSnapshotIs(t *testing.T, c *Module, expected bool) { } } +func assertExcludeFromRecoverySnapshotIs(t *testing.T, c *Module, expected bool) { + t.Helper() + if c.ExcludeFromRecoverySnapshot() != expected { + t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", c.String(), expected) + } +} + func TestVendorSnapshotExclude(t *testing.T) { // This test verifies that the exclude_from_vendor_snapshot property @@ -1667,7 +1674,7 @@ func TestRecoverySnapshotCapture(t *testing.T) { } ` config := TestConfig(buildDir, android.Android, nil, bp, nil) - config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") ctx := testCcWithConfig(t, config) @@ -1738,6 +1745,111 @@ func TestRecoverySnapshotCapture(t *testing.T) { } } +func TestRecoverySnapshotExclude(t *testing.T) { + // This test verifies that the exclude_from_recovery_snapshot property + // makes its way from the Android.bp source file into the module data + // structure. It also verifies that modules are correctly included or + // excluded in the recovery snapshot based on their path (framework or + // vendor) and the exclude_from_recovery_snapshot property. + + frameworkBp := ` + cc_library_shared { + name: "libinclude", + srcs: ["src/include.cpp"], + recovery_available: true, + } + cc_library_shared { + name: "libexclude", + srcs: ["src/exclude.cpp"], + recovery: true, + exclude_from_recovery_snapshot: true, + } + ` + + vendorProprietaryBp := ` + cc_library_shared { + name: "libvendor", + srcs: ["vendor.cpp"], + recovery: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "framework/include.cpp": nil, + "framework/exclude.cpp": nil, + "device/Android.bp": []byte(vendorProprietaryBp), + "device/vendor.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext(config) + ctx.Register() + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + // Test an include and exclude framework module. + assertExcludeFromRecoverySnapshotIs(t, ctx.ModuleForTests("libinclude", coreVariant).Module().(*Module), false) + assertExcludeFromRecoverySnapshotIs(t, ctx.ModuleForTests("libinclude", recoveryVariant).Module().(*Module), false) + assertExcludeFromRecoverySnapshotIs(t, ctx.ModuleForTests("libexclude", recoveryVariant).Module().(*Module), true) + + // A vendor module is excluded, but by its path, not the + // exclude_from_recovery_snapshot property. + assertExcludeFromRecoverySnapshotIs(t, ctx.ModuleForTests("libvendor", recoveryVariant).Module().(*Module), false) + + // Verify the content of the recovery snapshot. + + snapshotDir := "recovery-snapshot" + snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") + + var includeJsonFiles []string + var excludeJsonFiles []string + + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) + + // Excluded modules + checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) + checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json")) + } + + // Verify that each json file for an included module has a rule. + for _, jsonFile := range includeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("include json file %q not found", jsonFile) + } + } + + // Verify that each json file for an excluded module has no rule. + for _, jsonFile := range excludeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil { + t.Errorf("exclude json file %q found", jsonFile) + } + } +} + func TestDoubleLoadableDepError(t *testing.T) { // Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` diff --git a/cc/genrule.go b/cc/genrule.go index 3668e2bea..110652069 100644 --- a/cc/genrule.go +++ b/cc/genrule.go @@ -75,7 +75,15 @@ func (g *GenruleExtraProperties) VendorRamdiskVariantNeeded(ctx android.BaseModu } func (g *GenruleExtraProperties) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { - return Bool(g.Recovery_available) + // If the build is using a snapshot, the recovery variant under AOSP directories + // is not needed. + recoverySnapshotVersion := ctx.DeviceConfig().RecoverySnapshotVersion() + if recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" && + !isRecoveryProprietaryModule(ctx) { + return false + } else { + return Bool(g.Recovery_available) + } } func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleContext) []string { diff --git a/cc/image.go b/cc/image.go index 380c1dbe1..7f215e866 100644 --- a/cc/image.go +++ b/cc/image.go @@ -223,6 +223,9 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion() boardVndkVersion := mctx.DeviceConfig().VndkVersion() productVndkVersion := mctx.DeviceConfig().ProductVndkVersion() + recoverySnapshotVersion := mctx.DeviceConfig().RecoverySnapshotVersion() + usingRecoverySnapshot := recoverySnapshotVersion != "current" && + recoverySnapshotVersion != "" if boardVndkVersion == "current" { boardVndkVersion = platformVndkVersion } @@ -261,7 +264,11 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { if snapshot, ok := m.linker.(interface { version() string }); ok { - vendorVariants = append(vendorVariants, snapshot.version()) + if m.InstallInRecovery() { + recoveryVariantNeeded = true + } else { + vendorVariants = append(vendorVariants, snapshot.version()) + } } else { mctx.ModuleErrorf("version is unknown for snapshot prebuilt") } @@ -367,6 +374,15 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { coreVariantNeeded = false } + // If using a snapshot, the recovery variant under AOSP directories is not needed, + // except for kernel headers, which needs all variants. + if _, ok := m.linker.(*kernelHeadersDecorator); !ok && + !m.isSnapshotPrebuilt() && + usingRecoverySnapshot && + !isRecoveryProprietaryModule(mctx) { + recoveryVariantNeeded = false + } + for _, variant := range android.FirstUniqueStrings(vendorVariants) { m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant) } @@ -379,6 +395,14 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { m.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded m.Properties.CoreVariantNeeded = coreVariantNeeded + + // Disable the module if no variants are needed. + if !ramdiskVariantNeeded && + !recoveryVariantNeeded && + !coreVariantNeeded && + len(m.Properties.ExtraVariants) == 0 { + m.Disable() + } } func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool { diff --git a/cc/library.go b/cc/library.go index f4400a912..371075f95 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1846,9 +1846,8 @@ func CanBeOrLinkAgainstVersionVariants(module interface { Host() bool InRamdisk() bool InVendorRamdisk() bool - InRecovery() bool }) bool { - return !module.Host() && !module.InRamdisk() && !module.InVendorRamdisk() && !module.InRecovery() + return !module.Host() && !module.InRamdisk() && !module.InVendorRamdisk() } func CanBeVersionVariant(module interface { diff --git a/cc/makevars.go b/cc/makevars.go index bd8aab532..8301c6b38 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -99,6 +99,7 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "") ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion()) + ctx.Strict("RECOVERY_SNAPSHOT_VERSION", ctx.DeviceConfig().RecoverySnapshotVersion()) // Filter vendor_public_library that are exported to make exportedVendorPublicLibraries := []string{} diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go index 4c4e9b605..8c5d1a405 100644 --- a/cc/snapshot_prebuilt.go +++ b/cc/snapshot_prebuilt.go @@ -22,6 +22,8 @@ import ( "sync" "android/soong/android" + + "github.com/google/blueprint/proptools" ) // Defines the specifics of different images to which the snapshot process is applicable, e.g., @@ -30,6 +32,9 @@ type snapshotImage interface { // Used to register callbacks with the build system. init() + // 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. @@ -55,6 +60,28 @@ type snapshotImage interface { // snapshot, e.g., using the exclude_from_vendor_snapshot or // exclude_from_recovery_snapshot properties. excludeFromSnapshot(m *Module) bool + + // Returns the snapshotMap to be used for a given module and config, or nil if the + // module is not included in this image. + getSnapshotMap(m *Module, cfg android.Config) *snapshotMap + + // Returns mutex used for mutual exclusion when updating the snapshot maps. + getMutex() *sync.Mutex + + // For a given arch, a maps of which modules are included in this image. + suffixModules(config android.Config) map[string]bool + + // Whether to add a given module to the suffix map. + shouldBeAddedToSuffixModules(m *Module) bool + + // Returns true if the build is using a snapshot for this image. + isUsingSnapshot(cfg android.DeviceConfig) bool + + // Whether to skip the module mutator for a module in a given context. + skipModuleMutator(ctx android.BottomUpMutatorContext) bool + + // Whether to skip the source mutator for a given module. + skipSourceMutator(ctx android.BottomUpMutatorContext) bool } type vendorSnapshotImage struct{} @@ -69,6 +96,11 @@ func (vendorSnapshotImage) init() { android.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory) } +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 *Module) func() bool { return m.inVendor } @@ -90,6 +122,75 @@ func (vendorSnapshotImage) excludeFromSnapshot(m *Module) bool { return m.ExcludeFromVendorSnapshot() } +func (vendorSnapshotImage) getSnapshotMap(m *Module, cfg android.Config) *snapshotMap { + if lib, ok := m.linker.(libraryInterface); ok { + if lib.static() { + return vendorSnapshotStaticLibs(cfg) + } else if lib.shared() { + return vendorSnapshotSharedLibs(cfg) + } else { + // header + return vendorSnapshotHeaderLibs(cfg) + } + } else if m.binary() { + return vendorSnapshotBinaries(cfg) + } else if m.object() { + return vendorSnapshotObjects(cfg) + } else { + return nil + } +} + +func (vendorSnapshotImage) getMutex() *sync.Mutex { + return &vendorSnapshotsLock +} + +func (vendorSnapshotImage) suffixModules(config android.Config) map[string]bool { + return vendorSuffixModules(config) +} + +func (vendorSnapshotImage) shouldBeAddedToSuffixModules(module *Module) bool { + // vendor suffix should be added to snapshots if the source module isn't vendor: true. + if module.SocSpecific() { + return false + } + + // But we can't just check SocSpecific() since we already passed the image mutator. + // Check ramdisk and recovery to see if we are real "vendor: true" module. + ramdiskAvailable := module.InRamdisk() && !module.OnlyInRamdisk() + vendorRamdiskAvailable := module.InVendorRamdisk() && !module.OnlyInVendorRamdisk() + recoveryAvailable := module.InRecovery() && !module.OnlyInRecovery() + + return !ramdiskAvailable && !recoveryAvailable && !vendorRamdiskAvailable +} + +func (vendorSnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool { + vndkVersion := cfg.VndkVersion() + return vndkVersion != "current" && vndkVersion != "" +} + +func (vendorSnapshotImage) skipModuleMutator(ctx android.BottomUpMutatorContext) bool { + vndkVersion := ctx.DeviceConfig().VndkVersion() + module, ok := ctx.Module().(*Module) + return !ok || module.VndkVersion() != vndkVersion +} + +func (vendorSnapshotImage) skipSourceMutator(ctx android.BottomUpMutatorContext) bool { + vndkVersion := ctx.DeviceConfig().VndkVersion() + module, ok := ctx.Module().(*Module) + if !ok { + return true + } + if module.VndkVersion() != vndkVersion { + return true + } + // .. and also filter out llndk library + if module.IsLlndk() { + return true + } + return false +} + func (recoverySnapshotImage) init() { android.RegisterSingletonType("recovery-snapshot", RecoverySnapshotSingleton) android.RegisterModuleType("recovery_snapshot_shared", RecoverySnapshotSharedFactory) @@ -99,6 +200,12 @@ func (recoverySnapshotImage) init() { android.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 *Module) func() bool { return m.InRecovery } @@ -120,6 +227,52 @@ func (recoverySnapshotImage) excludeFromSnapshot(m *Module) bool { return m.ExcludeFromRecoverySnapshot() } +func (recoverySnapshotImage) getSnapshotMap(m *Module, cfg android.Config) *snapshotMap { + if lib, ok := m.linker.(libraryInterface); ok { + if lib.static() { + return recoverySnapshotStaticLibs(cfg) + } else if lib.shared() { + return recoverySnapshotSharedLibs(cfg) + } else { + // header + return recoverySnapshotHeaderLibs(cfg) + } + } else if m.binary() { + return recoverySnapshotBinaries(cfg) + } else if m.object() { + return recoverySnapshotObjects(cfg) + } else { + return nil + } +} + +func (recoverySnapshotImage) getMutex() *sync.Mutex { + return &recoverySnapshotsLock +} + +func (recoverySnapshotImage) suffixModules(config android.Config) map[string]bool { + return recoverySuffixModules(config) +} + +func (recoverySnapshotImage) shouldBeAddedToSuffixModules(module *Module) bool { + return proptools.BoolDefault(module.Properties.Recovery_available, false) +} + +func (recoverySnapshotImage) isUsingSnapshot(cfg android.DeviceConfig) bool { + recoverySnapshotVersion := cfg.RecoverySnapshotVersion() + return recoverySnapshotVersion != "current" && recoverySnapshotVersion != "" +} + +func (recoverySnapshotImage) skipModuleMutator(ctx android.BottomUpMutatorContext) bool { + module, ok := ctx.Module().(*Module) + return !ok || !module.InRecovery() +} + +func (recoverySnapshotImage) skipSourceMutator(ctx android.BottomUpMutatorContext) bool { + module, ok := ctx.Module().(*Module) + return !ok || !module.InRecovery() +} + var vendorSnapshotImageSingleton vendorSnapshotImage var recoverySnapshotImageSingleton recoverySnapshotImage @@ -154,6 +307,16 @@ var ( vendorSnapshotObjectsKey = android.NewOnceKey("vendorSnapshotObjects") ) +var ( + recoverySnapshotsLock sync.Mutex + recoverySuffixModulesKey = android.NewOnceKey("recoverySuffixModules") + recoverySnapshotHeaderLibsKey = android.NewOnceKey("recoverySnapshotHeaderLibs") + recoverySnapshotStaticLibsKey = android.NewOnceKey("recoverySnapshotStaticLibs") + recoverySnapshotSharedLibsKey = android.NewOnceKey("recoverySnapshotSharedLibs") + recoverySnapshotBinariesKey = android.NewOnceKey("recoverySnapshotBinaries") + recoverySnapshotObjectsKey = android.NewOnceKey("recoverySnapshotObjects") +) + // vendorSuffixModules holds names of modules whose vendor variants should have the vendor suffix. // This is determined by source modules, and then this will be used when exporting snapshot modules // to Makefile. @@ -200,12 +363,52 @@ func vendorSnapshotObjects(config android.Config) *snapshotMap { }).(*snapshotMap) } +func recoverySuffixModules(config android.Config) map[string]bool { + return config.Once(recoverySuffixModulesKey, func() interface{} { + return make(map[string]bool) + }).(map[string]bool) +} + +func recoverySnapshotHeaderLibs(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotHeaderLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func recoverySnapshotSharedLibs(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotSharedLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func recoverySnapshotStaticLibs(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotStaticLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func recoverySnapshotBinaries(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotBinariesKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func recoverySnapshotObjects(config android.Config) *snapshotMap { + return config.Once(recoverySnapshotObjectsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + type baseSnapshotDecoratorProperties struct { // snapshot version. Version string // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64') Target_arch string + + // Suffix to be added to the module name, e.g., vendor_shared, + // recovery_shared, etc. + Module_suffix string } // baseSnapshotDecorator provides common basic functions for all snapshot modules, such as snapshot @@ -222,7 +425,6 @@ type baseSnapshotDecoratorProperties struct { // will be seen as "libbase.vendor_static.30.arm64" by Soong. type baseSnapshotDecorator struct { baseProperties baseSnapshotDecoratorProperties - moduleSuffix string } func (p *baseSnapshotDecorator) Name(name string) string { @@ -235,7 +437,7 @@ func (p *baseSnapshotDecorator) NameSuffix() string { versionSuffix += "." + p.arch() } - return p.moduleSuffix + versionSuffix + return p.baseProperties.Module_suffix + versionSuffix } func (p *baseSnapshotDecorator) version() string { @@ -246,6 +448,10 @@ func (p *baseSnapshotDecorator) arch() string { return p.baseProperties.Target_arch } +func (p *baseSnapshotDecorator) module_suffix() string { + return p.baseProperties.Module_suffix +} + func (p *baseSnapshotDecorator) isSnapshotPrebuilt() bool { return true } @@ -253,7 +459,7 @@ func (p *baseSnapshotDecorator) isSnapshotPrebuilt() bool { // Call this with a module suffix after creating a snapshot module, such as // vendorSnapshotSharedSuffix, recoverySnapshotBinarySuffix, etc. func (p *baseSnapshotDecorator) init(m *Module, suffix string) { - p.moduleSuffix = suffix + p.baseProperties.Module_suffix = suffix m.AddProperties(&p.baseProperties) android.AddLoadHook(m, func(ctx android.LoadHookContext) { vendorSnapshotLoadHook(ctx, p) @@ -313,7 +519,7 @@ type snapshotLibraryDecorator struct { // Library flags for cfi variant. Cfi snapshotLibraryProperties `android:"arch_variant"` } - androidMkVendorSuffix bool + androidMkSuffix string } func (p *snapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { @@ -337,7 +543,12 @@ func (p *snapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig // done by normal library decorator, e.g. exporting flags. func (p *snapshotLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { m := ctx.Module().(*Module) - p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()] + + if m.inVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = vendorSuffix + } else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = recoverySuffix + } if p.header() { return p.libraryDecorator.link(ctx, flags, deps, objs) @@ -530,8 +741,8 @@ type snapshotBinaryProperties struct { type snapshotBinaryDecorator struct { baseSnapshotDecorator *binaryDecorator - properties snapshotBinaryProperties - androidMkVendorSuffix bool + properties snapshotBinaryProperties + androidMkSuffix string } func (p *snapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool { @@ -556,7 +767,12 @@ func (p *snapshotBinaryDecorator) link(ctx ModuleContext, flags Flags, deps Path binName := in.Base() m := ctx.Module().(*Module) - p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()] + if m.inVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = vendorSuffix + } else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = recoverySuffix + + } // use cpExecutable to make it executable outputFile := android.PathForModuleOut(ctx, binName) @@ -627,8 +843,8 @@ type vendorSnapshotObjectProperties struct { type snapshotObjectLinker struct { baseSnapshotDecorator objectLinker - properties vendorSnapshotObjectProperties - androidMkVendorSuffix bool + properties vendorSnapshotObjectProperties + androidMkSuffix string } func (p *snapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool { @@ -649,7 +865,12 @@ func (p *snapshotObjectLinker) link(ctx ModuleContext, flags Flags, deps PathDep } m := ctx.Module().(*Module) - p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()] + + if m.inVendor() && vendorSuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = vendorSuffix + } else if m.InRecovery() && recoverySuffixModules(ctx.Config())[m.BaseModuleName()] { + p.androidMkSuffix = recoverySuffix + } return android.PathForModuleSrc(ctx, *p.properties.Src) } @@ -717,17 +938,24 @@ var _ snapshotInterface = (*snapshotObjectLinker)(nil) // // TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) { - vndkVersion := ctx.DeviceConfig().VndkVersion() - // don't need snapshot if current - if vndkVersion == "current" || vndkVersion == "" { + snapshotMutator(ctx, vendorSnapshotImageSingleton) +} + +func RecoverySnapshotMutator(ctx android.BottomUpMutatorContext) { + snapshotMutator(ctx, recoverySnapshotImageSingleton) +} + +func snapshotMutator(ctx android.BottomUpMutatorContext, image snapshotImage) { + if !image.isUsingSnapshot(ctx.DeviceConfig()) { return } - module, ok := ctx.Module().(*Module) - if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion { + if !ok || !module.Enabled() { + return + } + if image.skipModuleMutator(ctx) { return } - if !module.isSnapshotPrebuilt() { return } @@ -742,39 +970,31 @@ func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) { return } - var snapshotMap *snapshotMap - - if lib, ok := module.linker.(libraryInterface); ok { - if lib.static() { - snapshotMap = vendorSnapshotStaticLibs(ctx.Config()) - } else if lib.shared() { - snapshotMap = vendorSnapshotSharedLibs(ctx.Config()) - } else { - // header - snapshotMap = vendorSnapshotHeaderLibs(ctx.Config()) - } - } else if _, ok := module.linker.(*snapshotBinaryDecorator); ok { - snapshotMap = vendorSnapshotBinaries(ctx.Config()) - } else if _, ok := module.linker.(*snapshotObjectLinker); ok { - snapshotMap = vendorSnapshotObjects(ctx.Config()) - } else { + var snapshotMap *snapshotMap = image.getSnapshotMap(module, ctx.Config()) + if snapshotMap == nil { return } - vendorSnapshotsLock.Lock() - defer vendorSnapshotsLock.Unlock() + mutex := image.getMutex() + mutex.Lock() + defer mutex.Unlock() snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName()) } // VendorSnapshotSourceMutator disables source modules which have corresponding snapshots. func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) { + snapshotSourceMutator(ctx, vendorSnapshotImageSingleton) +} + +func RecoverySnapshotSourceMutator(ctx android.BottomUpMutatorContext) { + snapshotSourceMutator(ctx, recoverySnapshotImageSingleton) +} + +func snapshotSourceMutator(ctx android.BottomUpMutatorContext, image snapshotImage) { if !ctx.Device() { return } - - vndkVersion := ctx.DeviceConfig().VndkVersion() - // don't need snapshot if current - if vndkVersion == "current" || vndkVersion == "" { + if !image.isUsingSnapshot(ctx.DeviceConfig()) { return } @@ -783,48 +1003,23 @@ func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) { return } - // vendor suffix should be added to snapshots if the source module isn't vendor: true. - if !module.SocSpecific() { - // But we can't just check SocSpecific() since we already passed the image mutator. - // Check ramdisk and recovery to see if we are real "vendor: true" module. - ramdiskAvailable := module.InRamdisk() && !module.OnlyInRamdisk() - vendorRamdiskAvailable := module.InVendorRamdisk() && !module.OnlyInVendorRamdisk() - recoveryAvailable := module.InRecovery() && !module.OnlyInRecovery() + if image.shouldBeAddedToSuffixModules(module) { + mutex := image.getMutex() + mutex.Lock() + defer mutex.Unlock() - if !ramdiskAvailable && !recoveryAvailable && !vendorRamdiskAvailable { - vendorSnapshotsLock.Lock() - defer vendorSnapshotsLock.Unlock() - - vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true - } + image.suffixModules(ctx.Config())[ctx.ModuleName()] = true } - if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() { - // only non-snapshot modules with BOARD_VNDK_VERSION + if module.isSnapshotPrebuilt() { + return + } + if image.skipSourceMutator(ctx) { return } - // .. and also filter out llndk library - if module.IsLlndk() { - return - } - - var snapshotMap *snapshotMap - - if lib, ok := module.linker.(libraryInterface); ok { - if lib.static() { - snapshotMap = vendorSnapshotStaticLibs(ctx.Config()) - } else if lib.shared() { - snapshotMap = vendorSnapshotSharedLibs(ctx.Config()) - } else { - // header - snapshotMap = vendorSnapshotHeaderLibs(ctx.Config()) - } - } else if module.binary() { - snapshotMap = vendorSnapshotBinaries(ctx.Config()) - } else if module.object() { - snapshotMap = vendorSnapshotObjects(ctx.Config()) - } else { + var snapshotMap *snapshotMap = image.getSnapshotMap(module, ctx.Config()) + if snapshotMap == nil { return } diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go index e841a547b..77d82f1b5 100644 --- a/cc/snapshot_utils.go +++ b/cc/snapshot_utils.go @@ -71,6 +71,10 @@ func (s *snapshotMap) get(name string, arch android.ArchType) (snapshot string, // shouldCollectHeadersForSnapshot determines if the module is a possible candidate for snapshot. // If it's true, collectHeadersForSnapshot will be called in GenerateAndroidBuildActions. func shouldCollectHeadersForSnapshot(ctx android.ModuleContext, m *Module, apexInfo android.ApexInfo) bool { + if ctx.DeviceConfig().VndkVersion() != "current" && + ctx.DeviceConfig().RecoverySnapshotVersion() != "current" { + return false + } if _, _, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo); ok { return ctx.Config().VndkSnapshotBuildArtifacts() } else if isVendorSnapshotAware(m, isVendorProprietaryPath(ctx.ModuleDir()), apexInfo) || diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index d2c29d631..417516bf9 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -85,7 +85,6 @@ var ( // Modules under following directories are ignored. They are OEM's and vendor's // proprietary modules(device/, kernel/, vendor/, and hardware/). recoveryProprietaryDirs = []string{ - "bootable/recovery", "device", "hardware", "kernel", @@ -156,6 +155,28 @@ func isVendorProprietaryModule(ctx android.BaseModuleContext) bool { return false } +func isRecoveryProprietaryModule(ctx android.BaseModuleContext) bool { + + // Any module in a vendor proprietary path is a vendor proprietary + // module. + if isRecoveryProprietaryPath(ctx.ModuleDir()) { + 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().(*Module); ok { + if c.ExcludeFromRecoverySnapshot() { + return true + } + } + + return false +} + // Determine if a module is going to be included in vendor snapshot or not. // // Targets of vendor snapshot are "vendor: true" or "vendor_available: true" modules in @@ -192,7 +213,7 @@ func isSnapshotAware(m *Module, inProprietaryPath bool, apexInfo android.ApexInf } // 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 m.ExcludeFromVendorSnapshot() { + if image.excludeFromSnapshot(m) { return false } if m.Target().Os.Class != android.Device { @@ -290,8 +311,7 @@ type snapshotJsonFlags struct { } func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { - // BOARD_VNDK_VERSION must be set to 'current' in order to generate a vendor snapshot. - if ctx.DeviceConfig().VndkVersion() != "current" { + if !c.image.shouldGenerateSnapshot(ctx) { return } @@ -480,7 +500,7 @@ func (c *snapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) { inProprietaryPath := c.image.isProprietaryPath(moduleDir) apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) - if m.ExcludeFromVendorSnapshot() { + if c.image.excludeFromSnapshot(m) { if inProprietaryPath { // Error: exclude_from_vendor_snapshot applies // to framework-path modules only.