From eec88e1de8861f221fec0644500a3f80c181f57e Mon Sep 17 00:00:00 2001 From: Inseob Kim Date: Wed, 22 Jan 2020 11:11:29 +0900 Subject: [PATCH] Add vendor snapshot modules This implements four modules (static/shared/header libraries, and binaries) for vendor snapshot. These modules will override source modules if BOARD_VNDK_VERSION != current. Bug: 65377115 Test: 1) VNDK_SNAPSHOT_BUILD_ARTIFACTS=true m dist vndk vendor-snapshot Test: 2) install snapshot under source tree Test: 3) set BOARD_VNDK_VERSION and boot cuttlefish Change-Id: I24ddb4c3aa6abeab60bbfd31bcbd8753e2592dc5 --- android/arch.go | 4 +- android/module.go | 5 + cc/androidmk.go | 60 +++++- cc/cc.go | 134 ++++++++++-- cc/sanitize.go | 46 ++++- cc/snapshot_utils.go | 27 +++ cc/vendor_snapshot.go | 461 ++++++++++++++++++++++++++++++++++++++++++ cc/vndk_prebuilt.go | 40 +++- 8 files changed, 742 insertions(+), 35 deletions(-) diff --git a/android/arch.go b/android/arch.go index 3657e6dd4..fb1acccda 100644 --- a/android/arch.go +++ b/android/arch.go @@ -765,7 +765,7 @@ func osMutator(mctx BottomUpMutatorContext) { } if len(moduleOSList) == 0 { - base.commonProperties.Enabled = boolPtr(false) + base.Disable() return } @@ -869,7 +869,7 @@ func archMutator(mctx BottomUpMutatorContext) { } if len(targets) == 0 { - base.commonProperties.Enabled = boolPtr(false) + base.Disable() return } diff --git a/android/module.go b/android/module.go index 0c732fb65..00825c337 100644 --- a/android/module.go +++ b/android/module.go @@ -204,6 +204,7 @@ type Module interface { DepsMutator(BottomUpMutatorContext) base() *ModuleBase + Disable() Enabled() bool Target() Target InstallInData() bool @@ -839,6 +840,10 @@ func (m *ModuleBase) Enabled() bool { return *m.commonProperties.Enabled } +func (m *ModuleBase) Disable() { + m.commonProperties.Enabled = proptools.BoolPtr(false) +} + func (m *ModuleBase) SkipInstall() { m.commonProperties.SkipInstall = true } diff --git a/cc/androidmk.go b/cc/androidmk.go index 137cb63d7..d8210fc9b 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -413,9 +413,12 @@ func (c *llndkStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.Androi } func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + // Each vndk prebuilt is exported to androidMk only when BOARD_VNDK_VERSION != current + // and the version of the prebuilt is same as BOARD_VNDK_VERSION. ret.Class = "SHARED_LIBRARIES" - ret.SubName = c.NameSuffix() + // shouldn't add any suffixes due to mk modules + ret.SubName = "" ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { c.libraryDecorator.androidMkWriteExportedFlags(w) @@ -426,6 +429,61 @@ func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *andr fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix) fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path) fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) + if c.tocFile.Valid() { + fmt.Fprintln(w, "LOCAL_SOONG_TOC := "+c.tocFile.String()) + } + }) +} + +func (c *vendorSnapshotLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + // Each vendor snapshot is exported to androidMk only when BOARD_VNDK_VERSION != current + // and the version of the prebuilt is same as BOARD_VNDK_VERSION. + if c.shared() { + ret.Class = "SHARED_LIBRARIES" + } else if c.static() { + ret.Class = "STATIC_LIBRARIES" + } else if c.header() { + ret.Class = "HEADER_LIBRARIES" + } + + if c.androidMkVendorSuffix { + ret.SubName = vendorSuffix + } else { + ret.SubName = "" + } + + ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { + c.libraryDecorator.androidMkWriteExportedFlags(w) + + if c.shared() { + path, file := filepath.Split(c.path.ToMakePath().String()) + stem, suffix, ext := android.SplitFileExt(file) + fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+ext) + fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix) + if c.shared() { + fmt.Fprintln(w, "LOCAL_MODULE_PATH := "+path) + fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) + } + if c.tocFile.Valid() { + fmt.Fprintln(w, "LOCAL_SOONG_TOC := "+c.tocFile.String()) + } + } else { // static or header + fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") + } + }) +} + +func (c *vendorSnapshotBinaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ret.Class = "EXECUTABLES" + + if c.androidMkVendorSuffix { + ret.SubName = vendorSuffix + } else { + ret.SubName = "" + } + + ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { + fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS := "+strings.Join(c.Properties.Symlinks, " ")) }) } diff --git a/cc/cc.go b/cc/cc.go index bef922a1f..b4ac52659 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -49,6 +49,8 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.BottomUp("version", VersionMutator).Parallel() ctx.BottomUp("begin", BeginMutator).Parallel() ctx.BottomUp("sysprop_cc", SyspropMutator).Parallel() + ctx.BottomUp("vendor_snapshot", VendorSnapshotMutator).Parallel() + ctx.BottomUp("vendor_snapshot_source", VendorSnapshotSourceMutator).Parallel() }) ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { @@ -933,8 +935,16 @@ func (c *Module) nativeCoverage() bool { } func (c *Module) isSnapshotPrebuilt() bool { - _, ok := c.linker.(*vndkPrebuiltLibraryDecorator) - return ok + if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok { + return true + } + if _, ok := c.linker.(*vendorSnapshotLibraryDecorator); ok { + return true + } + if _, ok := c.linker.(*vendorSnapshotBinaryDecorator); ok { + return true + } + return false } func (c *Module) ExportedIncludeDirs() android.Paths { @@ -1631,6 +1641,10 @@ func StubsLibNameAndVersion(name string) (string, string) { } func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { + if !c.Enabled() { + return + } + ctx := &depsContext{ BottomUpMutatorContext: actx, moduleContextImpl: moduleContextImpl{ @@ -1646,7 +1660,7 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if ctx.Os() == android.Android { version := ctx.sdkVersion() - // rewriteNdkLibs takes a list of names of shared libraries and scans it for three types + // rewriteLibs takes a list of names of shared libraries and scans it for three types // of names: // // 1. Name of an NDK library that refers to a prebuilt module. @@ -1662,7 +1676,26 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { // nonvariantLibs vendorPublicLibraries := vendorPublicLibraries(actx.Config()) - rewriteNdkLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) { + vendorSnapshotSharedLibs := vendorSnapshotSharedLibs(actx.Config()) + + rewriteVendorLibs := func(lib string) string { + if isLlndkLibrary(lib, ctx.Config()) { + return lib + llndkLibrarySuffix + } + + // only modules with BOARD_VNDK_VERSION uses snapshot. + if c.VndkVersion() != actx.DeviceConfig().VndkVersion() { + return lib + } + + if snapshot, ok := vendorSnapshotSharedLibs.get(lib, actx.Arch().ArchType); ok { + return snapshot + } + + return lib + } + + rewriteLibs := func(list []string) (nonvariantLibs []string, variantLibs []string) { variantLibs = []string{} nonvariantLibs = []string{} for _, entry := range list { @@ -1674,8 +1707,8 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } else { variantLibs = append(variantLibs, name+ndkLibrarySuffix) } - } else if ctx.useVndk() && isLlndkLibrary(name, ctx.Config()) { - nonvariantLibs = append(nonvariantLibs, name+llndkLibrarySuffix) + } else if ctx.useVndk() { + nonvariantLibs = append(nonvariantLibs, rewriteVendorLibs(entry)) } else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) { vendorPublicLib := name + vendorPublicLibrarySuffix if actx.OtherModuleExists(vendorPublicLib) { @@ -1694,9 +1727,14 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { return nonvariantLibs, variantLibs } - deps.SharedLibs, variantNdkLibs = rewriteNdkLibs(deps.SharedLibs) - deps.LateSharedLibs, variantLateNdkLibs = rewriteNdkLibs(deps.LateSharedLibs) - deps.ReexportSharedLibHeaders, _ = rewriteNdkLibs(deps.ReexportSharedLibHeaders) + deps.SharedLibs, variantNdkLibs = rewriteLibs(deps.SharedLibs) + deps.LateSharedLibs, variantLateNdkLibs = rewriteLibs(deps.LateSharedLibs) + deps.ReexportSharedLibHeaders, _ = rewriteLibs(deps.ReexportSharedLibHeaders) + if ctx.useVndk() { + for idx, lib := range deps.RuntimeLibs { + deps.RuntimeLibs[idx] = rewriteVendorLibs(lib) + } + } } buildStubs := false @@ -1708,11 +1746,28 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } } + rewriteSnapshotLibs := func(lib string, snapshotMap *snapshotMap) string { + // only modules with BOARD_VNDK_VERSION uses snapshot. + if c.VndkVersion() != actx.DeviceConfig().VndkVersion() { + return lib + } + + if snapshot, ok := snapshotMap.get(lib, actx.Arch().ArchType); ok { + return snapshot + } + + return lib + } + + vendorSnapshotHeaderLibs := vendorSnapshotHeaderLibs(actx.Config()) for _, lib := range deps.HeaderLibs { depTag := headerDepTag if inList(lib, deps.ReexportHeaderLibHeaders) { depTag = headerExportDepTag } + + lib = rewriteSnapshotLibs(lib, vendorSnapshotHeaderLibs) + if buildStubs { actx.AddFarVariationDependencies(append(ctx.Target().Variations(), c.ImageVariation()), depTag, lib) @@ -1728,12 +1783,16 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } syspropImplLibraries := syspropImplLibraries(actx.Config()) + vendorSnapshotStaticLibs := vendorSnapshotStaticLibs(actx.Config()) for _, lib := range deps.WholeStaticLibs { depTag := wholeStaticDepTag if impl, ok := syspropImplLibraries[lib]; ok { lib = impl } + + lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs) + actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, }, depTag, lib) @@ -1749,14 +1808,18 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { lib = impl } + lib = rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs) + actx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, }, depTag, lib) } - actx.AddVariationDependencies([]blueprint.Variation{ - {Mutator: "link", Variation: "static"}, - }, lateStaticDepTag, deps.LateStaticLibs...) + for _, lib := range deps.LateStaticLibs { + actx.AddVariationDependencies([]blueprint.Variation{ + {Mutator: "link", Variation: "static"}, + }, lateStaticDepTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs)) + } addSharedLibDependencies := func(depTag DependencyTag, name string, version string) { var variations []blueprint.Variation @@ -2300,14 +2363,33 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { *depPtr = append(*depPtr, dep.Path()) } - makeLibName := func(depName string) string { + vendorSuffixModules := vendorSuffixModules(ctx.Config()) + + baseLibName := func(depName string) string { libName := strings.TrimSuffix(depName, llndkLibrarySuffix) libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix) libName = strings.TrimPrefix(libName, "prebuilt_") + return libName + } + + makeLibName := func(depName string) string { + libName := baseLibName(depName) isLLndk := isLlndkLibrary(libName, ctx.Config()) isVendorPublicLib := inList(libName, *vendorPublicLibraries) bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk + if c, ok := ccDep.(*Module); ok { + // Use base module name for snapshots when exporting to Makefile. + if c.isSnapshotPrebuilt() && !c.IsVndk() { + baseName := c.BaseModuleName() + if vendorSuffixModules[baseName] { + return baseName + ".vendor" + } else { + return baseName + } + } + } + if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRamdisk() && !c.InRecovery() { // The vendor module is a no-vendor-variant VNDK library. Depend on the // core module instead. @@ -2347,8 +2429,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // they merely serve as Make dependencies and do not affect this lib itself. c.Properties.AndroidMkSharedLibs = append( c.Properties.AndroidMkSharedLibs, makeLibName(depName)) - // Record depName as-is for snapshots. - c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, depName) + // Record baseLibName for snapshots. + c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, baseLibName(depName)) case ndkStubDepTag, ndkLateStubDepTag: c.Properties.AndroidMkSharedLibs = append( c.Properties.AndroidMkSharedLibs, @@ -2359,8 +2441,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { case runtimeDepTag: c.Properties.AndroidMkRuntimeLibs = append( c.Properties.AndroidMkRuntimeLibs, makeLibName(depName)) - // Record depName as-is for snapshots. - c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, depName) + // Record baseLibName for snapshots. + c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName)) case wholeStaticDepTag: c.Properties.AndroidMkWholeStaticLibs = append( c.Properties.AndroidMkWholeStaticLibs, makeLibName(depName)) @@ -2733,10 +2815,16 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { platformVndkVersion, productVndkVersion, ) - } else if lib, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok { + } else if m.isSnapshotPrebuilt() { // Make vendor variants only for the versions in BOARD_VNDK_VERSION and // PRODUCT_EXTRA_VNDK_VERSIONS. - vendorVariants = append(vendorVariants, lib.version()) + if snapshot, ok := m.linker.(interface { + version() string + }); ok { + vendorVariants = append(vendorVariants, snapshot.version()) + } else { + mctx.ModuleErrorf("version is unknown for snapshot prebuilt") + } } else if m.HasVendorVariant() && !vendorSpecific { // This will be available in /system, /vendor and /product // or a /system directory that is available to vendor and product. @@ -2833,6 +2921,14 @@ func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string m.Properties.ImageVariationPrefix = VendorVariationPrefix m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix) squashVendorSrcs(m) + + // Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION. + // Hide other vendor variants to avoid collision. + vndkVersion := ctx.DeviceConfig().VndkVersion() + if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion { + m.Properties.HideFromMake = true + m.SkipInstall() + } } else if strings.HasPrefix(variant, ProductVariationPrefix) { m.Properties.ImageVariationPrefix = ProductVariationPrefix m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix) diff --git a/cc/sanitize.go b/cc/sanitize.go index 6f9dbef63..5663aa7ae 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -350,6 +350,12 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Diag.Cfi = nil } + // Also disable CFI if building against snapshot. + vndkVersion := ctx.DeviceConfig().VndkVersion() + if ctx.useVndk() && vndkVersion != "current" && vndkVersion != "" { + s.Cfi = nil + } + // HWASan ramdisk (which is built from recovery) goes over some bootloader limit. // Keep libc instrumented so that ramdisk / recovery can run hwasan-instrumented code if necessary. if (ctx.inRamdisk() || ctx.inRecovery()) && !strings.HasPrefix(ctx.ModuleDir(), "bionic/libc") { @@ -739,7 +745,11 @@ func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { return false } - if d, ok := child.(*Module); ok && d.static() && d.sanitize != nil { + d, ok := child.(*Module) + if !ok || !d.static() { + return false + } + if d.sanitize != nil { if enableMinimalRuntime(d.sanitize) { // If a static dependency is built with the minimal runtime, // make sure we include the ubsan minimal runtime. @@ -757,9 +767,18 @@ func sanitizerRuntimeDepsMutator(mctx android.TopDownMutatorContext) { } return true - } else { - return false } + + if p, ok := d.linker.(*vendorSnapshotLibraryDecorator); ok { + if Bool(p.properties.Sanitize_minimal_dep) { + c.sanitize.Properties.MinimalRuntimeDep = true + } + if Bool(p.properties.Sanitize_ubsan_dep) { + c.sanitize.Properties.UbsanRuntimeDep = true + } + } + + return false }) } } @@ -900,12 +919,31 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { // Note that by adding dependency with {static|shared}DepTag, the lib is // added to libFlags and LOCAL_SHARED_LIBRARIES by cc.Module if c.staticBinary() { + deps := append(extraStaticDeps, runtimeLibrary) + // If we're using snapshots and in vendor, redirect to snapshot whenever possible + if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() { + snapshots := vendorSnapshotStaticLibs(mctx.Config()) + for idx, dep := range deps { + if lib, ok := snapshots.get(dep, mctx.Arch().ArchType); ok { + deps[idx] = lib + } + } + } + // static executable gets static runtime libs mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{ {Mutator: "link", Variation: "static"}, c.ImageVariation(), - }...), StaticDepTag, append([]string{runtimeLibrary}, extraStaticDeps...)...) + }...), StaticDepTag, deps...) } else if !c.static() && !c.header() { + // If we're using snapshots and in vendor, redirect to snapshot whenever possible + if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() { + snapshots := vendorSnapshotSharedLibs(mctx.Config()) + if lib, ok := snapshots.get(runtimeLibrary, mctx.Arch().ArchType); ok { + runtimeLibrary = lib + } + } + // dynamic executable and shared libs get shared runtime libs mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{ {Mutator: "link", Variation: "shared"}, diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go index 1c872c2c9..8f48f869b 100644 --- a/cc/snapshot_utils.go +++ b/cc/snapshot_utils.go @@ -31,6 +31,33 @@ type snapshotLibraryInterface interface { var _ snapshotLibraryInterface = (*prebuiltLibraryLinker)(nil) var _ snapshotLibraryInterface = (*libraryDecorator)(nil) +type snapshotMap struct { + snapshots map[string]string +} + +func newSnapshotMap() *snapshotMap { + return &snapshotMap{ + snapshots: make(map[string]string), + } +} + +func snapshotMapKey(name string, arch android.ArchType) string { + return name + ":" + arch.String() +} + +// Adds a snapshot name for given module name and architecture. +// e.g. add("libbase", X86, "libbase.vndk.29.x86") +func (s *snapshotMap) add(name string, arch android.ArchType, snapshot string) { + s.snapshots[snapshotMapKey(name, arch)] = snapshot +} + +// Returns snapshot name for given module name and architecture, if found. +// e.g. get("libcutils", X86) => "libcutils.vndk.29.x86", true +func (s *snapshotMap) get(name string, arch android.ArchType) (snapshot string, found bool) { + snapshot, found = s.snapshots[snapshotMapKey(name, arch)] + return snapshot, found +} + func exportedHeaders(ctx android.SingletonContext, l exportedFlagsProducer) android.Paths { var ret android.Paths diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index d952a4cb1..d92caa1e1 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -18,14 +18,358 @@ import ( "path/filepath" "sort" "strings" + "sync" "github.com/google/blueprint/proptools" "android/soong/android" ) +const ( + vendorSnapshotHeaderSuffix = ".vendor_header." + vendorSnapshotSharedSuffix = ".vendor_shared." + vendorSnapshotStaticSuffix = ".vendor_static." + vendorSnapshotBinarySuffix = ".vendor_binary." +) + +var ( + vendorSnapshotsLock sync.Mutex + vendorSuffixModulesKey = android.NewOnceKey("vendorSuffixModules") + vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs") + vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs") + vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs") + vendorSnapshotBinariesKey = android.NewOnceKey("vendorSnapshotBinaries") +) + +// vendor snapshot maps hold names of vendor snapshot modules per arch. +func vendorSuffixModules(config android.Config) map[string]bool { + return config.Once(vendorSuffixModulesKey, func() interface{} { + return make(map[string]bool) + }).(map[string]bool) +} + +func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func vendorSnapshotSharedLibs(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotSharedLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func vendorSnapshotStaticLibs(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotStaticLibsKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +func vendorSnapshotBinaries(config android.Config) *snapshotMap { + return config.Once(vendorSnapshotBinariesKey, func() interface{} { + return newSnapshotMap() + }).(*snapshotMap) +} + +type vendorSnapshotLibraryProperties struct { + // snapshot version. + Version string + + // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64') + Target_arch string + + // Prebuilt file for each arch. + Src *string `android:"arch_variant"` + + // list of flags that will be used for any module that links against this module. + Export_flags []string `android:"arch_variant"` + + // Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined symbols, + // etc). + Check_elf_files *bool + + // Whether this prebuilt needs to depend on sanitize ubsan runtime or not. + Sanitize_ubsan_dep *bool `android:"arch_variant"` + + // Whether this prebuilt needs to depend on sanitize minimal runtime or not. + Sanitize_minimal_dep *bool `android:"arch_variant"` +} + +type vendorSnapshotLibraryDecorator struct { + *libraryDecorator + properties vendorSnapshotLibraryProperties + androidMkVendorSuffix bool +} + +func (p *vendorSnapshotLibraryDecorator) Name(name string) string { + return name + p.NameSuffix() +} + +func (p *vendorSnapshotLibraryDecorator) NameSuffix() string { + versionSuffix := p.version() + if p.arch() != "" { + versionSuffix += "." + p.arch() + } + + var linkageSuffix string + if p.buildShared() { + linkageSuffix = vendorSnapshotSharedSuffix + } else if p.buildStatic() { + linkageSuffix = vendorSnapshotStaticSuffix + } else { + linkageSuffix = vendorSnapshotHeaderSuffix + } + + return linkageSuffix + versionSuffix +} + +func (p *vendorSnapshotLibraryDecorator) version() string { + return p.properties.Version +} + +func (p *vendorSnapshotLibraryDecorator) arch() string { + return p.properties.Target_arch +} + +func (p *vendorSnapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { + p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix()) + return p.libraryDecorator.linkerFlags(ctx, flags) +} + +func (p *vendorSnapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool { + arches := config.Arches() + if len(arches) == 0 || arches[0].ArchType.String() != p.arch() { + return false + } + if !p.header() && p.properties.Src == nil { + return false + } + return true +} + +func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext, + flags Flags, deps PathDeps, objs Objects) android.Path { + m := ctx.Module().(*Module) + p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()] + + if p.header() { + return p.libraryDecorator.link(ctx, flags, deps, objs) + } + + if !p.matchesWithDevice(ctx.DeviceConfig()) { + return nil + } + + p.libraryDecorator.exportIncludes(ctx) + p.libraryDecorator.reexportFlags(p.properties.Export_flags...) + + in := android.PathForModuleSrc(ctx, *p.properties.Src) + p.unstrippedOutputFile = in + + if p.shared() { + libName := in.Base() + builderFlags := flagsToBuilderFlags(flags) + + // Optimize out relinking against shared libraries whose interface hasn't changed by + // depending on a table of contents file instead of the library itself. + tocFile := android.PathForModuleOut(ctx, libName+".toc") + p.tocFile = android.OptionalPathForPath(tocFile) + TransformSharedObjectToToc(ctx, in, tocFile, builderFlags) + } + + return in +} + +func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool { + return false +} + +func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) { + if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) { + p.baseInstaller.install(ctx, file) + } +} + +type vendorSnapshotInterface interface { + version() string +} + +func vendorSnapshotLoadHook(ctx android.LoadHookContext, p vendorSnapshotInterface) { + if p.version() != ctx.DeviceConfig().VndkVersion() { + ctx.Module().Disable() + return + } +} + +func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) { + module, library := NewLibrary(android.DeviceSupported) + + module.stl = nil + module.sanitize = nil + library.StripProperties.Strip.None = BoolPtr(true) + + prebuilt := &vendorSnapshotLibraryDecorator{ + libraryDecorator: library, + } + + prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true) + prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true) + + // Prevent default system libs (libc, libm, and libdl) from being linked + if prebuilt.baseLinker.Properties.System_shared_libs == nil { + prebuilt.baseLinker.Properties.System_shared_libs = []string{} + } + + module.compiler = nil + module.linker = prebuilt + module.installer = prebuilt + + module.AddProperties( + &prebuilt.properties, + ) + + return module, prebuilt +} + +func VendorSnapshotSharedFactory() android.Module { + module, prebuilt := vendorSnapshotLibrary() + prebuilt.libraryDecorator.BuildOnlyShared() + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + vendorSnapshotLoadHook(ctx, prebuilt) + }) + return module.Init() +} + +func VendorSnapshotStaticFactory() android.Module { + module, prebuilt := vendorSnapshotLibrary() + prebuilt.libraryDecorator.BuildOnlyStatic() + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + vendorSnapshotLoadHook(ctx, prebuilt) + }) + return module.Init() +} + +func VendorSnapshotHeaderFactory() android.Module { + module, prebuilt := vendorSnapshotLibrary() + prebuilt.libraryDecorator.HeaderOnly() + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + vendorSnapshotLoadHook(ctx, prebuilt) + }) + return module.Init() +} + +type vendorSnapshotBinaryProperties struct { + // snapshot version. + Version string + + // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab') + Target_arch string + + // Prebuilt file for each arch. + Src *string `android:"arch_variant"` +} + +type vendorSnapshotBinaryDecorator struct { + *binaryDecorator + properties vendorSnapshotBinaryProperties + androidMkVendorSuffix bool +} + +func (p *vendorSnapshotBinaryDecorator) Name(name string) string { + return name + p.NameSuffix() +} + +func (p *vendorSnapshotBinaryDecorator) NameSuffix() string { + versionSuffix := p.version() + if p.arch() != "" { + versionSuffix += "." + p.arch() + } + return vendorSnapshotBinarySuffix + versionSuffix +} + +func (p *vendorSnapshotBinaryDecorator) version() string { + return p.properties.Version +} + +func (p *vendorSnapshotBinaryDecorator) arch() string { + return p.properties.Target_arch +} + +func (p *vendorSnapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool { + if config.DeviceArch() != p.arch() { + return false + } + if p.properties.Src == nil { + return false + } + return true +} + +func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext, + flags Flags, deps PathDeps, objs Objects) android.Path { + if !p.matchesWithDevice(ctx.DeviceConfig()) { + return nil + } + + in := android.PathForModuleSrc(ctx, *p.properties.Src) + builderFlags := flagsToBuilderFlags(flags) + p.unstrippedOutputFile = in + binName := in.Base() + if p.needsStrip(ctx) { + stripped := android.PathForModuleOut(ctx, "stripped", binName) + p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + in = stripped + } + + m := ctx.Module().(*Module) + p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()] + + // use cpExecutable to make it executable + outputFile := android.PathForModuleOut(ctx, binName) + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpExecutable, + Description: "prebuilt", + Output: outputFile, + Input: in, + }) + + return outputFile +} + +func VendorSnapshotBinaryFactory() android.Module { + module, binary := NewBinary(android.DeviceSupported) + binary.baseLinker.Properties.No_libcrt = BoolPtr(true) + binary.baseLinker.Properties.Nocrt = BoolPtr(true) + + // Prevent default system libs (libc, libm, and libdl) from being linked + if binary.baseLinker.Properties.System_shared_libs == nil { + binary.baseLinker.Properties.System_shared_libs = []string{} + } + + prebuilt := &vendorSnapshotBinaryDecorator{ + binaryDecorator: binary, + } + + module.compiler = nil + module.sanitize = nil + module.stl = nil + module.linker = prebuilt + + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + vendorSnapshotLoadHook(ctx, prebuilt) + }) + + module.AddProperties(&prebuilt.properties) + return module.Init() +} + func init() { android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton) + android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory) + android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) + android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory) + android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory) } func VendorSnapshotSingleton() android.Singleton { @@ -367,3 +711,120 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont func (c *vendorSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) { ctx.Strict("SOONG_VENDOR_SNAPSHOT_ZIP", c.vendorSnapshotZipFile.String()) } + +type snapshotInterface interface { + matchesWithDevice(config android.DeviceConfig) bool +} + +var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil) +var _ snapshotInterface = (*vendorSnapshotLibraryDecorator)(nil) +var _ snapshotInterface = (*vendorSnapshotBinaryDecorator)(nil) + +// gathers all snapshot modules for vendor, and disable unnecessary snapshots +// 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 == "" { + return + } + + module, ok := ctx.Module().(*Module) + if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion { + return + } + + snapshot, ok := module.linker.(snapshotInterface) + if !ok { + return + } + + if !snapshot.matchesWithDevice(ctx.DeviceConfig()) { + // Disable unnecessary snapshot module, but do not disable + // vndk_prebuilt_shared because they might be packed into vndk APEX + if !module.IsVndk() { + module.Disable() + } + 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.(*vendorSnapshotBinaryDecorator); ok { + snapshotMap = vendorSnapshotBinaries(ctx.Config()) + } else { + return + } + + vendorSnapshotsLock.Lock() + defer vendorSnapshotsLock.Unlock() + snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName()) +} + +// Disables source modules which have snapshots +func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) { + vndkVersion := ctx.DeviceConfig().VndkVersion() + // don't need snapshot if current + if vndkVersion == "current" || vndkVersion == "" { + return + } + + module, ok := ctx.Module().(*Module) + if !ok { + return + } + + if module.HasVendorVariant() { + vendorSnapshotsLock.Lock() + defer vendorSnapshotsLock.Unlock() + + vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true + } + + if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() { + // only non-snapshot modules with BOARD_VNDK_VERSION + 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.(*binaryDecorator); ok { + snapshotMap = vendorSnapshotBinaries(ctx.Config()) + } else if _, ok := module.linker.(*prebuiltBinaryLinker); ok { + snapshotMap = vendorSnapshotBinaries(ctx.Config()) + } else { + return + } + + if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok { + // Corresponding snapshot doesn't exist + return + } + + // Disables source modules if corresponding snapshot exists. + if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() { + // But do not disable because the shared variant depends on the static variant. + module.SkipInstall() + module.Properties.HideFromMake = true + } else { + module.Disable() + } +} diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index c941c4691..50bc32592 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -31,7 +31,8 @@ var ( // // vndk_prebuilt_shared { // name: "libfoo", -// version: "27.1.0", +// version: "27", +// target_arch: "arm64", // vendor_available: true, // vndk: { // enabled: true, @@ -61,10 +62,6 @@ type vndkPrebuiltProperties struct { // Prebuilt files for each arch. Srcs []string `android:"arch_variant"` - // list of directories relative to the Blueprints file that will be added to the include - // path (using -isystem) for any module that links against this module. - Export_system_include_dirs []string `android:"arch_variant"` - // list of flags that will be used for any module that links against this module. Export_flags []string `android:"arch_variant"` @@ -137,11 +134,26 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, if len(p.properties.Srcs) > 0 && p.shared() { p.libraryDecorator.exportIncludes(ctx) - p.libraryDecorator.reexportSystemDirs( - android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...) p.libraryDecorator.reexportFlags(p.properties.Export_flags...) // current VNDK prebuilts are only shared libs. - return p.singleSourcePath(ctx) + + in := p.singleSourcePath(ctx) + builderFlags := flagsToBuilderFlags(flags) + p.unstrippedOutputFile = in + libName := in.Base() + if p.needsStrip(ctx) { + stripped := android.PathForModuleOut(ctx, "stripped", libName) + p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + in = stripped + } + + // Optimize out relinking against shared libraries whose interface hasn't changed by + // depending on a table of contents file instead of the library itself. + tocFile := android.PathForModuleOut(ctx, libName+".toc") + p.tocFile = android.OptionalPathForPath(tocFile) + TransformSharedObjectToToc(ctx, in, tocFile, builderFlags) + + return in } ctx.Module().SkipInstall() @@ -212,6 +224,15 @@ func vndkPrebuiltSharedLibrary() *Module { &prebuilt.properties, ) + android.AddLoadHook(module, func(ctx android.LoadHookContext) { + // Only vndk snapshots of BOARD_VNDK_VERSION will be used when building. + if prebuilt.version() != ctx.DeviceConfig().VndkVersion() { + module.SkipInstall() + module.Properties.HideFromMake = true + return + } + }) + return module } @@ -220,7 +241,8 @@ func vndkPrebuiltSharedLibrary() *Module { // // vndk_prebuilt_shared { // name: "libfoo", -// version: "27.1.0", +// version: "27", +// target_arch: "arm64", // vendor_available: true, // vndk: { // enabled: true,