Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eaebec13 authored by Inseob Kim's avatar Inseob Kim Committed by Gerrit Code Review
Browse files

Merge changes from topic "cfi_vendor_snapshot"

* changes:
  Add cfi static libraries to vendor snapshot
  Refactor vendor snapshot modules
parents 8b073fc7 c42f2f2e
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -518,10 +518,14 @@ func (c *vendorSnapshotLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext,
		entries.Class = "HEADER_LIBRARIES"
	}

	if c.androidMkVendorSuffix {
		entries.SubName = vendorSuffix
	} else {
	entries.SubName = ""

	if c.sanitizerProperties.CfiEnabled {
		entries.SubName += ".cfi"
	}

	if c.androidMkVendorSuffix {
		entries.SubName += vendorSuffix
	}

	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+42 −1
Original line number Diff line number Diff line
@@ -1013,17 +1013,25 @@ func TestVendorSnapshot(t *testing.T) {
			filepath.Join(sharedDir, "libvendor_available.so.json"))

		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
		// Also cfi variants are captured, except for prebuilts like toolchain_library
		staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
		staticCfiVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static_cfi", archType, archVariant)
		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant)
		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.cfi.a", staticDir, staticCfiVariant)
		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant)
		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.cfi.a", staticDir, staticCfiVariant)
		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.cfi.a", staticDir, staticCfiVariant)
		jsonFiles = append(jsonFiles,
			filepath.Join(staticDir, "libb.a.json"),
			filepath.Join(staticDir, "libvndk.a.json"),
			filepath.Join(staticDir, "libvndk.cfi.a.json"),
			filepath.Join(staticDir, "libvendor.a.json"),
			filepath.Join(staticDir, "libvendor_available.a.json"))
			filepath.Join(staticDir, "libvendor.cfi.a.json"),
			filepath.Join(staticDir, "libvendor_available.a.json"),
			filepath.Join(staticDir, "libvendor_available.cfi.a.json"))

		// For binary executables, all vendor:true and vendor_available modules are captured.
		if archType == "arm64" {
@@ -1055,6 +1063,39 @@ func TestVendorSnapshot(t *testing.T) {
	}
}

func TestVendorSnapshotSanitizer(t *testing.T) {
	bp := `
	vendor_snapshot_static {
		name: "libsnapshot",
		vendor: true,
		target_arch: "arm64",
		version: "BOARD",
		arch: {
			arm64: {
				src: "libsnapshot.a",
				cfi: {
					src: "libsnapshot.cfi.a",
				}
			},
		},
	}
`
	config := TestConfig(buildDir, android.Android, nil, bp, nil)
	config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
	ctx := testCcWithConfig(t, config)

	// Check non-cfi and cfi variant.
	staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
	staticCfiVariant := "android_vendor.BOARD_arm64_armv8-a_static_cfi"

	staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticVariant).Module().(*Module)
	assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a")

	staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticCfiVariant).Module().(*Module)
	assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
}

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", `
+88 −32
Original line number Diff line number Diff line
@@ -321,14 +321,14 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {

	// Is CFI actually enabled?
	if !ctx.Config().EnableCFI() {
		s.Cfi = nil
		s.Diag.Cfi = nil
		s.Cfi = boolPtr(false)
		s.Diag.Cfi = boolPtr(false)
	}

	// Also disable CFI for arm32 until b/35157333 is fixed.
	if ctx.Arch().ArchType == android.Arm {
		s.Cfi = nil
		s.Diag.Cfi = nil
		s.Cfi = boolPtr(false)
		s.Diag.Cfi = boolPtr(false)
	}

	// HWASan requires AArch64 hardware feature (top-byte-ignore).
@@ -343,14 +343,14 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {

	// Also disable CFI if ASAN is enabled.
	if Bool(s.Address) || Bool(s.Hwaddress) {
		s.Cfi = nil
		s.Diag.Cfi = nil
		s.Cfi = boolPtr(false)
		s.Diag.Cfi = boolPtr(false)
	}

	// Disable sanitizers that depend on the UBSan runtime for windows/darwin builds.
	if !ctx.Os().Linux() {
		s.Cfi = nil
		s.Diag.Cfi = nil
		s.Cfi = boolPtr(false)
		s.Diag.Cfi = boolPtr(false)
		s.Misc_undefined = nil
		s.Undefined = nil
		s.All_undefined = nil
@@ -359,14 +359,15 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {

	// Also disable CFI for VNDK variants of components
	if ctx.isVndk() && ctx.useVndk() {
		if ctx.static() {
			// Cfi variant for static vndk should be captured as vendor snapshot,
			// so don't strictly disable Cfi.
			s.Cfi = nil
			s.Diag.Cfi = nil
		} else {
			s.Cfi = boolPtr(false)
			s.Diag.Cfi = boolPtr(false)
		}

	// 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.
@@ -411,7 +412,7 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) {
	// TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is
	// mutually incompatible.
	if Bool(s.Fuzzer) {
		s.Cfi = nil
		s.Cfi = boolPtr(false)
	}
}

@@ -741,10 +742,46 @@ func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
	}
}

// Determines if the current module is a static library going to be captured
// 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 isVendorProprietaryPath(mctx.ModuleDir()) {
		return false
	}

	c := mctx.Module().(*Module)

	if !c.inVendor() {
		return false
	}

	if !c.static() {
		return false
	}

	if c.Prebuilt() != nil {
		return false
	}

	return c.sanitize != nil &&
		!Bool(c.sanitize.Properties.Sanitize.Never) &&
		!c.sanitize.isSanitizerExplicitlyDisabled(cfi)
}

// Propagate sanitizer requirements down from binaries
func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) {
	return func(mctx android.TopDownMutatorContext) {
		if c, ok := mctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(t) {
		if c, ok := mctx.Module().(*Module); ok {
			enabled := c.sanitize.isSanitizerEnabled(t)
			if t == cfi && needsCfiForVendorSnapshot(mctx) {
				// We shouldn't change the result of isSanitizerEnabled(cfi) to correctly
				// determine defaultVariation in sanitizerMutator below.
				// Instead, just mark SanitizeDep to forcefully create cfi variant.
				enabled = true
				c.sanitize.Properties.SanitizeDep = true
			}
			if enabled {
				mctx.WalkDeps(func(child, parent android.Module) bool {
					if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
						return false
@@ -762,6 +799,7 @@ func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) {
					}
					return true
				})
			}
		} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
			// If an APEX module includes a lib which is enabled for a sanitizer T, then
			// the APEX module is also enabled for the same sanitizer type.
@@ -1095,6 +1133,24 @@ func sanitizerMutator(t sanitizerType) func(android.BottomUpMutatorContext) {
			// APEX modules fall here
			sanitizeable.AddSanitizerDependencies(mctx, t.name())
			mctx.CreateVariations(t.variationName())
		} else if c, ok := mctx.Module().(*Module); ok {
			// Check if it's a snapshot module supporting sanitizer
			if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) {
				// Set default variation as above.
				defaultVariation := t.variationName()
				mctx.SetDefaultDependencyVariation(&defaultVariation)
				modules := mctx.CreateVariations("", t.variationName())
				modules[0].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, false)
				modules[1].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, true)

				// Export the static lib name to make
				if c.static() && c.ExportedToMake() {
					if t == cfi {
						// use BaseModuleName which is the name for Make.
						cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
					}
				}
			}
		}
	}
}
+1 −0
Original line number Diff line number Diff line
@@ -567,6 +567,7 @@ func CreateTestContext() *android.TestContext {
	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
	ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
	ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
	ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
	android.RegisterPrebuiltMutators(ctx)
	RegisterRequiredBuildComponentsForTest(ctx)
+125 −130
Original line number Diff line number Diff line
@@ -80,64 +80,98 @@ func vendorSnapshotObjects(config android.Config) *snapshotMap {
	}).(*snapshotMap)
}

type vendorSnapshotLibraryProperties struct {
type vendorSnapshotBaseProperties 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"`
// vendorSnapshotModuleBase provides common basic functions for all snapshot modules.
type vendorSnapshotModuleBase struct {
	baseProperties vendorSnapshotBaseProperties
	moduleSuffix   string
}

	// list of flags that will be used for any module that links against this module.
	Export_flags []string `android:"arch_variant"`
func (p *vendorSnapshotModuleBase) Name(name string) string {
	return name + p.NameSuffix()
}

	// Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined symbols,
	// etc).
	Check_elf_files *bool
func (p *vendorSnapshotModuleBase) NameSuffix() string {
	versionSuffix := p.version()
	if p.arch() != "" {
		versionSuffix += "." + p.arch()
	}

	// Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
	Sanitize_ubsan_dep *bool `android:"arch_variant"`
	return p.moduleSuffix + versionSuffix
}

	// Whether this prebuilt needs to depend on sanitize minimal runtime or not.
	Sanitize_minimal_dep *bool `android:"arch_variant"`
func (p *vendorSnapshotModuleBase) version() string {
	return p.baseProperties.Version
}

type vendorSnapshotLibraryDecorator struct {
	*libraryDecorator
	properties            vendorSnapshotLibraryProperties
	androidMkVendorSuffix bool
func (p *vendorSnapshotModuleBase) arch() string {
	return p.baseProperties.Target_arch
}

func (p *vendorSnapshotLibraryDecorator) Name(name string) string {
	return name + p.NameSuffix()
func (p *vendorSnapshotModuleBase) isSnapshotPrebuilt() bool {
	return true
}

func (p *vendorSnapshotLibraryDecorator) NameSuffix() string {
	versionSuffix := p.version()
	if p.arch() != "" {
		versionSuffix += "." + p.arch()
// Call this after creating a snapshot module with module suffix
// such as vendorSnapshotSharedSuffix
func (p *vendorSnapshotModuleBase) init(m *Module, suffix string) {
	p.moduleSuffix = suffix
	m.AddProperties(&p.baseProperties)
	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
		vendorSnapshotLoadHook(ctx, p)
	})
}

	var linkageSuffix string
	if p.buildShared() {
		linkageSuffix = vendorSnapshotSharedSuffix
	} else if p.buildStatic() {
		linkageSuffix = vendorSnapshotStaticSuffix
	} else {
		linkageSuffix = vendorSnapshotHeaderSuffix
func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *vendorSnapshotModuleBase) {
	if p.version() != ctx.DeviceConfig().VndkVersion() {
		ctx.Module().Disable()
		return
	}
}

type vendorSnapshotLibraryProperties struct {
	// Prebuilt file for each arch.
	Src *string `android:"arch_variant"`

	// list of directories that will be added to the include path (using -I).
	Export_include_dirs []string `android:"arch_variant"`

	// list of directories that will be added to the system path (using -isystem).
	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"`

	// Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
	Sanitize_ubsan_dep *bool `android:"arch_variant"`

	return linkageSuffix + versionSuffix
	// Whether this prebuilt needs to depend on sanitize minimal runtime or not.
	Sanitize_minimal_dep *bool `android:"arch_variant"`
}

func (p *vendorSnapshotLibraryDecorator) version() string {
	return p.properties.Version
type snapshotSanitizer interface {
	isSanitizerEnabled(t sanitizerType) bool
	setSanitizerVariation(t sanitizerType, enabled bool)
}

func (p *vendorSnapshotLibraryDecorator) arch() string {
	return p.properties.Target_arch
type vendorSnapshotLibraryDecorator struct {
	vendorSnapshotModuleBase
	*libraryDecorator
	properties          vendorSnapshotLibraryProperties
	sanitizerProperties struct {
		CfiEnabled bool `blueprint:"mutated"`

		// Library flags for cfi variant.
		Cfi vendorSnapshotLibraryProperties `android:"arch_variant"`
	}
	androidMkVendorSuffix bool
}

func (p *vendorSnapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
@@ -165,11 +199,16 @@ func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext,
		return p.libraryDecorator.link(ctx, flags, deps, objs)
	}

	if p.sanitizerProperties.CfiEnabled {
		p.properties = p.sanitizerProperties.Cfi
	}

	if !p.matchesWithDevice(ctx.DeviceConfig()) {
		return nil
	}

	p.libraryDecorator.exportIncludes(ctx)
	p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...)
	p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
	p.libraryDecorator.reexportFlags(p.properties.Export_flags...)

	in := android.PathForModuleSrc(ctx, *p.properties.Src)
@@ -189,32 +228,38 @@ func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext,
	return in
}

func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool {
	return false
}

func (p *vendorSnapshotLibraryDecorator) isSnapshotPrebuilt() bool {
	return true
}

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 (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool {
	return false
}

func vendorSnapshotLoadHook(ctx android.LoadHookContext, p vendorSnapshotInterface) {
	if p.version() != ctx.DeviceConfig().VndkVersion() {
		ctx.Module().Disable()
func (p *vendorSnapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool {
	switch t {
	case cfi:
		return p.sanitizerProperties.Cfi.Src != nil
	default:
		return false
	}
}

func (p *vendorSnapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) {
	if !enabled {
		return
	}
	switch t {
	case cfi:
		p.sanitizerProperties.CfiEnabled = true
	default:
		return
	}
}

func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) {
func vendorSnapshotLibrary(suffix string) (*Module, *vendorSnapshotLibraryDecorator) {
	module, library := NewLibrary(android.DeviceSupported)

	module.stl = nil
@@ -237,77 +282,47 @@ func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) {
	module.linker = prebuilt
	module.installer = prebuilt

	prebuilt.init(module, suffix)
	module.AddProperties(
		&prebuilt.properties,
		&prebuilt.sanitizerProperties,
	)

	return module, prebuilt
}

func VendorSnapshotSharedFactory() android.Module {
	module, prebuilt := vendorSnapshotLibrary()
	module, prebuilt := vendorSnapshotLibrary(vendorSnapshotSharedSuffix)
	prebuilt.libraryDecorator.BuildOnlyShared()
	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
		vendorSnapshotLoadHook(ctx, prebuilt)
	})
	return module.Init()
}

func VendorSnapshotStaticFactory() android.Module {
	module, prebuilt := vendorSnapshotLibrary()
	module, prebuilt := vendorSnapshotLibrary(vendorSnapshotStaticSuffix)
	prebuilt.libraryDecorator.BuildOnlyStatic()
	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
		vendorSnapshotLoadHook(ctx, prebuilt)
	})
	return module.Init()
}

func VendorSnapshotHeaderFactory() android.Module {
	module, prebuilt := vendorSnapshotLibrary()
	module, prebuilt := vendorSnapshotLibrary(vendorSnapshotHeaderSuffix)
	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
var _ snapshotSanitizer = (*vendorSnapshotLibraryDecorator)(nil)

type vendorSnapshotBinaryProperties struct {
	// Prebuilt file for each arch.
	Src *string `android:"arch_variant"`
}

type vendorSnapshotBinaryDecorator struct {
	vendorSnapshotModuleBase
	*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
@@ -349,8 +364,8 @@ func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext,
	return outputFile
}

func (p *vendorSnapshotBinaryDecorator) isSnapshotPrebuilt() bool {
	return true
func (p *vendorSnapshotBinaryDecorator) nativeCoverage() bool {
	return false
}

func VendorSnapshotBinaryFactory() android.Module {
@@ -372,51 +387,23 @@ func VendorSnapshotBinaryFactory() android.Module {
	module.stl = nil
	module.linker = prebuilt

	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
		vendorSnapshotLoadHook(ctx, prebuilt)
	})

	prebuilt.init(module, vendorSnapshotBinarySuffix)
	module.AddProperties(&prebuilt.properties)
	return module.Init()
}

type vendorSnapshotObjectProperties 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 vendorSnapshotObjectLinker struct {
	vendorSnapshotModuleBase
	objectLinker
	properties            vendorSnapshotObjectProperties
	androidMkVendorSuffix bool
}

func (p *vendorSnapshotObjectLinker) Name(name string) string {
	return name + p.NameSuffix()
}

func (p *vendorSnapshotObjectLinker) NameSuffix() string {
	versionSuffix := p.version()
	if p.arch() != "" {
		versionSuffix += "." + p.arch()
	}
	return vendorSnapshotObjectSuffix + versionSuffix
}

func (p *vendorSnapshotObjectLinker) version() string {
	return p.properties.Version
}

func (p *vendorSnapshotObjectLinker) arch() string {
	return p.properties.Target_arch
}

func (p *vendorSnapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
	if config.DeviceArch() != p.arch() {
		return false
@@ -443,10 +430,6 @@ func (p *vendorSnapshotObjectLinker) nativeCoverage() bool {
	return false
}

func (p *vendorSnapshotObjectLinker) isSnapshotPrebuilt() bool {
	return true
}

func VendorSnapshotObjectFactory() android.Module {
	module := newObject()

@@ -457,10 +440,7 @@ func VendorSnapshotObjectFactory() android.Module {
	}
	module.linker = prebuilt

	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
		vendorSnapshotLoadHook(ctx, prebuilt)
	})

	prebuilt.init(module, vendorSnapshotObjectSuffix)
	module.AddProperties(&prebuilt.properties)
	return module.Init()
}
@@ -568,13 +548,17 @@ func isVendorSnapshotModule(m *Module, moduleDir string) bool {
	if l, ok := m.linker.(snapshotLibraryInterface); ok {
		// TODO(b/65377115): add full support for sanitizer
		if m.sanitize != nil {
			// cfi, scs and hwasan export both sanitized and unsanitized variants for static and header
			// scs and hwasan export both sanitized and unsanitized variants for static and header
			// Always use unsanitized variants of them.
			for _, t := range []sanitizerType{cfi, scs, hwasan} {
			for _, t := range []sanitizerType{scs, hwasan} {
				if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
					return false
				}
			}
			// cfi also exports both variants. But for static, we capture both.
			if !l.static() && !l.shared() && m.sanitize.isSanitizerEnabled(cfi) {
				return false
			}
		}
		if l.static() {
			return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
@@ -668,6 +652,7 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont
			ExportedDirs       []string `json:",omitempty"`
			ExportedSystemDirs []string `json:",omitempty"`
			ExportedFlags      []string `json:",omitempty"`
			Sanitize           string   `json:",omitempty"`
			SanitizeMinimalDep bool     `json:",omitempty"`
			SanitizeUbsanDep   bool     `json:",omitempty"`

@@ -717,6 +702,7 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont
		var propOut string

		if l, ok := m.linker.(snapshotLibraryInterface); ok {

			// library flags
			prop.ExportedFlags = l.exportedFlags()
			for _, dir := range l.exportedDirs() {
@@ -749,6 +735,15 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont
			if libType != "header" {
				libPath := m.outputFile.Path()
				stem = libPath.Base()
				if l.static() && m.sanitize != nil && m.sanitize.isSanitizerEnabled(cfi) {
					// both cfi and non-cfi variant for static libraries can exist.
					// attach .cfi to distinguish between cfi and non-cfi.
					// e.g. libbase.a -> libbase.cfi.a
					ext := filepath.Ext(stem)
					stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext
					prop.Sanitize = "cfi"
					prop.ModuleName += ".cfi"
				}
				snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
			} else {