1// Copyright 2020 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14package cc
15
16import (
17	"encoding/json"
18	"path/filepath"
19	"sort"
20	"strings"
21	"sync"
22
23	"github.com/google/blueprint/proptools"
24
25	"android/soong/android"
26)
27
28const (
29	vendorSnapshotHeaderSuffix = ".vendor_header."
30	vendorSnapshotSharedSuffix = ".vendor_shared."
31	vendorSnapshotStaticSuffix = ".vendor_static."
32	vendorSnapshotBinarySuffix = ".vendor_binary."
33	vendorSnapshotObjectSuffix = ".vendor_object."
34)
35
36var (
37	vendorSnapshotsLock         sync.Mutex
38	vendorSuffixModulesKey      = android.NewOnceKey("vendorSuffixModules")
39	vendorSnapshotHeaderLibsKey = android.NewOnceKey("vendorSnapshotHeaderLibs")
40	vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs")
41	vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs")
42	vendorSnapshotBinariesKey   = android.NewOnceKey("vendorSnapshotBinaries")
43	vendorSnapshotObjectsKey    = android.NewOnceKey("vendorSnapshotObjects")
44)
45
46// vendor snapshot maps hold names of vendor snapshot modules per arch
47func vendorSuffixModules(config android.Config) map[string]bool {
48	return config.Once(vendorSuffixModulesKey, func() interface{} {
49		return make(map[string]bool)
50	}).(map[string]bool)
51}
52
53func vendorSnapshotHeaderLibs(config android.Config) *snapshotMap {
54	return config.Once(vendorSnapshotHeaderLibsKey, func() interface{} {
55		return newSnapshotMap()
56	}).(*snapshotMap)
57}
58
59func vendorSnapshotSharedLibs(config android.Config) *snapshotMap {
60	return config.Once(vendorSnapshotSharedLibsKey, func() interface{} {
61		return newSnapshotMap()
62	}).(*snapshotMap)
63}
64
65func vendorSnapshotStaticLibs(config android.Config) *snapshotMap {
66	return config.Once(vendorSnapshotStaticLibsKey, func() interface{} {
67		return newSnapshotMap()
68	}).(*snapshotMap)
69}
70
71func vendorSnapshotBinaries(config android.Config) *snapshotMap {
72	return config.Once(vendorSnapshotBinariesKey, func() interface{} {
73		return newSnapshotMap()
74	}).(*snapshotMap)
75}
76
77func vendorSnapshotObjects(config android.Config) *snapshotMap {
78	return config.Once(vendorSnapshotObjectsKey, func() interface{} {
79		return newSnapshotMap()
80	}).(*snapshotMap)
81}
82
83type vendorSnapshotLibraryProperties struct {
84	// snapshot version.
85	Version string
86
87	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
88	Target_arch string
89
90	// Prebuilt file for each arch.
91	Src *string `android:"arch_variant"`
92
93	// list of flags that will be used for any module that links against this module.
94	Export_flags []string `android:"arch_variant"`
95
96	// Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined symbols,
97	// etc).
98	Check_elf_files *bool
99
100	// Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
101	Sanitize_ubsan_dep *bool `android:"arch_variant"`
102
103	// Whether this prebuilt needs to depend on sanitize minimal runtime or not.
104	Sanitize_minimal_dep *bool `android:"arch_variant"`
105}
106
107type vendorSnapshotLibraryDecorator struct {
108	*libraryDecorator
109	properties            vendorSnapshotLibraryProperties
110	androidMkVendorSuffix bool
111}
112
113func (p *vendorSnapshotLibraryDecorator) Name(name string) string {
114	return name + p.NameSuffix()
115}
116
117func (p *vendorSnapshotLibraryDecorator) NameSuffix() string {
118	versionSuffix := p.version()
119	if p.arch() != "" {
120		versionSuffix += "." + p.arch()
121	}
122
123	var linkageSuffix string
124	if p.buildShared() {
125		linkageSuffix = vendorSnapshotSharedSuffix
126	} else if p.buildStatic() {
127		linkageSuffix = vendorSnapshotStaticSuffix
128	} else {
129		linkageSuffix = vendorSnapshotHeaderSuffix
130	}
131
132	return linkageSuffix + versionSuffix
133}
134
135func (p *vendorSnapshotLibraryDecorator) version() string {
136	return p.properties.Version
137}
138
139func (p *vendorSnapshotLibraryDecorator) arch() string {
140	return p.properties.Target_arch
141}
142
143func (p *vendorSnapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
144	p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix())
145	return p.libraryDecorator.linkerFlags(ctx, flags)
146}
147
148func (p *vendorSnapshotLibraryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
149	arches := config.Arches()
150	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
151		return false
152	}
153	if !p.header() && p.properties.Src == nil {
154		return false
155	}
156	return true
157}
158
159func (p *vendorSnapshotLibraryDecorator) link(ctx ModuleContext,
160	flags Flags, deps PathDeps, objs Objects) android.Path {
161	m := ctx.Module().(*Module)
162	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
163
164	if p.header() {
165		return p.libraryDecorator.link(ctx, flags, deps, objs)
166	}
167
168	if !p.matchesWithDevice(ctx.DeviceConfig()) {
169		return nil
170	}
171
172	p.libraryDecorator.exportIncludes(ctx)
173	p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
174
175	in := android.PathForModuleSrc(ctx, *p.properties.Src)
176	p.unstrippedOutputFile = in
177
178	if p.shared() {
179		libName := in.Base()
180		builderFlags := flagsToBuilderFlags(flags)
181
182		// Optimize out relinking against shared libraries whose interface hasn't changed by
183		// depending on a table of contents file instead of the library itself.
184		tocFile := android.PathForModuleOut(ctx, libName+".toc")
185		p.tocFile = android.OptionalPathForPath(tocFile)
186		TransformSharedObjectToToc(ctx, in, tocFile, builderFlags)
187	}
188
189	return in
190}
191
192func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool {
193	return false
194}
195
196func (p *vendorSnapshotLibraryDecorator) isSnapshotPrebuilt() bool {
197	return true
198}
199
200func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
201	if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) {
202		p.baseInstaller.install(ctx, file)
203	}
204}
205
206type vendorSnapshotInterface interface {
207	version() string
208}
209
210func vendorSnapshotLoadHook(ctx android.LoadHookContext, p vendorSnapshotInterface) {
211	if p.version() != ctx.DeviceConfig().VndkVersion() {
212		ctx.Module().Disable()
213		return
214	}
215}
216
217func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) {
218	module, library := NewLibrary(android.DeviceSupported)
219
220	module.stl = nil
221	module.sanitize = nil
222	library.StripProperties.Strip.None = BoolPtr(true)
223
224	prebuilt := &vendorSnapshotLibraryDecorator{
225		libraryDecorator: library,
226	}
227
228	prebuilt.baseLinker.Properties.No_libcrt = BoolPtr(true)
229	prebuilt.baseLinker.Properties.Nocrt = BoolPtr(true)
230
231	// Prevent default system libs (libc, libm, and libdl) from being linked
232	if prebuilt.baseLinker.Properties.System_shared_libs == nil {
233		prebuilt.baseLinker.Properties.System_shared_libs = []string{}
234	}
235
236	module.compiler = nil
237	module.linker = prebuilt
238	module.installer = prebuilt
239
240	module.AddProperties(
241		&prebuilt.properties,
242	)
243
244	return module, prebuilt
245}
246
247func VendorSnapshotSharedFactory() android.Module {
248	module, prebuilt := vendorSnapshotLibrary()
249	prebuilt.libraryDecorator.BuildOnlyShared()
250	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
251		vendorSnapshotLoadHook(ctx, prebuilt)
252	})
253	return module.Init()
254}
255
256func VendorSnapshotStaticFactory() android.Module {
257	module, prebuilt := vendorSnapshotLibrary()
258	prebuilt.libraryDecorator.BuildOnlyStatic()
259	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
260		vendorSnapshotLoadHook(ctx, prebuilt)
261	})
262	return module.Init()
263}
264
265func VendorSnapshotHeaderFactory() android.Module {
266	module, prebuilt := vendorSnapshotLibrary()
267	prebuilt.libraryDecorator.HeaderOnly()
268	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
269		vendorSnapshotLoadHook(ctx, prebuilt)
270	})
271	return module.Init()
272}
273
274type vendorSnapshotBinaryProperties struct {
275	// snapshot version.
276	Version string
277
278	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab')
279	Target_arch string
280
281	// Prebuilt file for each arch.
282	Src *string `android:"arch_variant"`
283}
284
285type vendorSnapshotBinaryDecorator struct {
286	*binaryDecorator
287	properties            vendorSnapshotBinaryProperties
288	androidMkVendorSuffix bool
289}
290
291func (p *vendorSnapshotBinaryDecorator) Name(name string) string {
292	return name + p.NameSuffix()
293}
294
295func (p *vendorSnapshotBinaryDecorator) NameSuffix() string {
296	versionSuffix := p.version()
297	if p.arch() != "" {
298		versionSuffix += "." + p.arch()
299	}
300	return vendorSnapshotBinarySuffix + versionSuffix
301}
302
303func (p *vendorSnapshotBinaryDecorator) version() string {
304	return p.properties.Version
305}
306
307func (p *vendorSnapshotBinaryDecorator) arch() string {
308	return p.properties.Target_arch
309}
310
311func (p *vendorSnapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
312	if config.DeviceArch() != p.arch() {
313		return false
314	}
315	if p.properties.Src == nil {
316		return false
317	}
318	return true
319}
320
321func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext,
322	flags Flags, deps PathDeps, objs Objects) android.Path {
323	if !p.matchesWithDevice(ctx.DeviceConfig()) {
324		return nil
325	}
326
327	in := android.PathForModuleSrc(ctx, *p.properties.Src)
328	builderFlags := flagsToBuilderFlags(flags)
329	p.unstrippedOutputFile = in
330	binName := in.Base()
331	if p.needsStrip(ctx) {
332		stripped := android.PathForModuleOut(ctx, "stripped", binName)
333		p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
334		in = stripped
335	}
336
337	m := ctx.Module().(*Module)
338	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
339
340	// use cpExecutable to make it executable
341	outputFile := android.PathForModuleOut(ctx, binName)
342	ctx.Build(pctx, android.BuildParams{
343		Rule:        android.CpExecutable,
344		Description: "prebuilt",
345		Output:      outputFile,
346		Input:       in,
347	})
348
349	return outputFile
350}
351
352func (p *vendorSnapshotBinaryDecorator) isSnapshotPrebuilt() bool {
353	return true
354}
355
356func VendorSnapshotBinaryFactory() android.Module {
357	module, binary := NewBinary(android.DeviceSupported)
358	binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
359	binary.baseLinker.Properties.Nocrt = BoolPtr(true)
360
361	// Prevent default system libs (libc, libm, and libdl) from being linked
362	if binary.baseLinker.Properties.System_shared_libs == nil {
363		binary.baseLinker.Properties.System_shared_libs = []string{}
364	}
365
366	prebuilt := &vendorSnapshotBinaryDecorator{
367		binaryDecorator: binary,
368	}
369
370	module.compiler = nil
371	module.sanitize = nil
372	module.stl = nil
373	module.linker = prebuilt
374
375	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
376		vendorSnapshotLoadHook(ctx, prebuilt)
377	})
378
379	module.AddProperties(&prebuilt.properties)
380	return module.Init()
381}
382
383type vendorSnapshotObjectProperties struct {
384	// snapshot version.
385	Version string
386
387	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab')
388	Target_arch string
389
390	// Prebuilt file for each arch.
391	Src *string `android:"arch_variant"`
392}
393
394type vendorSnapshotObjectLinker struct {
395	objectLinker
396	properties            vendorSnapshotObjectProperties
397	androidMkVendorSuffix bool
398}
399
400func (p *vendorSnapshotObjectLinker) Name(name string) string {
401	return name + p.NameSuffix()
402}
403
404func (p *vendorSnapshotObjectLinker) NameSuffix() string {
405	versionSuffix := p.version()
406	if p.arch() != "" {
407		versionSuffix += "." + p.arch()
408	}
409	return vendorSnapshotObjectSuffix + versionSuffix
410}
411
412func (p *vendorSnapshotObjectLinker) version() string {
413	return p.properties.Version
414}
415
416func (p *vendorSnapshotObjectLinker) arch() string {
417	return p.properties.Target_arch
418}
419
420func (p *vendorSnapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
421	if config.DeviceArch() != p.arch() {
422		return false
423	}
424	if p.properties.Src == nil {
425		return false
426	}
427	return true
428}
429
430func (p *vendorSnapshotObjectLinker) link(ctx ModuleContext,
431	flags Flags, deps PathDeps, objs Objects) android.Path {
432	if !p.matchesWithDevice(ctx.DeviceConfig()) {
433		return nil
434	}
435
436	m := ctx.Module().(*Module)
437	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
438
439	return android.PathForModuleSrc(ctx, *p.properties.Src)
440}
441
442func (p *vendorSnapshotObjectLinker) nativeCoverage() bool {
443	return false
444}
445
446func (p *vendorSnapshotObjectLinker) isSnapshotPrebuilt() bool {
447	return true
448}
449
450func VendorSnapshotObjectFactory() android.Module {
451	module := newObject()
452
453	prebuilt := &vendorSnapshotObjectLinker{
454		objectLinker: objectLinker{
455			baseLinker: NewBaseLinker(nil),
456		},
457	}
458	module.linker = prebuilt
459
460	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
461		vendorSnapshotLoadHook(ctx, prebuilt)
462	})
463
464	module.AddProperties(&prebuilt.properties)
465	return module.Init()
466}
467
468func init() {
469	android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
470	android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
471	android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
472	android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory)
473	android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
474	android.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory)
475}
476
477func VendorSnapshotSingleton() android.Singleton {
478	return &vendorSnapshotSingleton{}
479}
480
481type vendorSnapshotSingleton struct {
482	vendorSnapshotZipFile android.OptionalPath
483}
484
485var (
486	// Modules under following directories are ignored. They are OEM's and vendor's
487	// proprietary modules(device/, vendor/, and hardware/).
488	// TODO(b/65377115): Clean up these with more maintainable way
489	vendorProprietaryDirs = []string{
490		"device",
491		"vendor",
492		"hardware",
493	}
494
495	// Modules under following directories are included as they are in AOSP,
496	// although hardware/ is normally for vendor's own.
497	// TODO(b/65377115): Clean up these with more maintainable way
498	aospDirsUnderProprietary = []string{
499		"hardware/interfaces",
500		"hardware/libhardware",
501		"hardware/libhardware_legacy",
502		"hardware/ril",
503	}
504)
505
506// Determine if a dir under source tree is an SoC-owned proprietary directory, such as
507// device/, vendor/, etc.
508func isVendorProprietaryPath(dir string) bool {
509	for _, p := range vendorProprietaryDirs {
510		if strings.HasPrefix(dir, p) {
511			// filter out AOSP defined directories, e.g. hardware/interfaces/
512			aosp := false
513			for _, p := range aospDirsUnderProprietary {
514				if strings.HasPrefix(dir, p) {
515					aosp = true
516					break
517				}
518			}
519			if !aosp {
520				return true
521			}
522		}
523	}
524	return false
525}
526
527// Determine if a module is going to be included in vendor snapshot or not.
528//
529// Targets of vendor snapshot are "vendor: true" or "vendor_available: true" modules in
530// AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might
531// depend on newer VNDK) So they are captured as vendor snapshot To build older vendor
532// image and newer system image altogether.
533func isVendorSnapshotModule(m *Module, moduleDir string) bool {
534	if !m.Enabled() || m.Properties.HideFromMake {
535		return false
536	}
537	// skip proprietary modules, but include all VNDK (static)
538	if isVendorProprietaryPath(moduleDir) && !m.IsVndk() {
539		return false
540	}
541	if m.Target().Os.Class != android.Device {
542		return false
543	}
544	if m.Target().NativeBridge == android.NativeBridgeEnabled {
545		return false
546	}
547	// the module must be installed in /vendor
548	if !m.IsForPlatform() || m.isSnapshotPrebuilt() || !m.inVendor() {
549		return false
550	}
551	// skip kernel_headers which always depend on vendor
552	if _, ok := m.linker.(*kernelHeadersDecorator); ok {
553		return false
554	}
555	// skip llndk_library and llndk_headers which are backward compatible
556	if _, ok := m.linker.(*llndkStubDecorator); ok {
557		return false
558	}
559	if _, ok := m.linker.(*llndkHeadersDecorator); ok {
560		return false
561	}
562
563	// Libraries
564	if l, ok := m.linker.(snapshotLibraryInterface); ok {
565		// TODO(b/65377115): add full support for sanitizer
566		if m.sanitize != nil {
567			// cfi, scs and hwasan export both sanitized and unsanitized variants for static and header
568			// Always use unsanitized variants of them.
569			for _, t := range []sanitizerType{cfi, scs, hwasan} {
570				if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
571					return false
572				}
573			}
574		}
575		if l.static() {
576			return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
577		}
578		if l.shared() {
579			if !m.outputFile.Valid() {
580				return false
581			}
582			if !m.IsVndk() {
583				return true
584			}
585			return m.isVndkExt()
586		}
587		return true
588	}
589
590	// Binaries and Objects
591	if m.binary() || m.object() {
592		return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
593	}
594
595	return false
596}
597
598func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
599	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a vendor snapshot.
600	if ctx.DeviceConfig().VndkVersion() != "current" {
601		return
602	}
603
604	var snapshotOutputs android.Paths
605
606	/*
607		Vendor snapshot zipped artifacts directory structure:
608		{SNAPSHOT_ARCH}/
609			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
610				shared/
611					(.so shared libraries)
612				static/
613					(.a static libraries)
614				header/
615					(header only libraries)
616				binary/
617					(executable binaries)
618				object/
619					(.o object files)
620			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
621				shared/
622					(.so shared libraries)
623				static/
624					(.a static libraries)
625				header/
626					(header only libraries)
627				binary/
628					(executable binaries)
629				object/
630					(.o object files)
631			NOTICE_FILES/
632				(notice files, e.g. libbase.txt)
633			configs/
634				(config files, e.g. init.rc files, vintf_fragments.xml files, etc.)
635			include/
636				(header files of same directory structure with source tree)
637	*/
638
639	snapshotDir := "vendor-snapshot"
640	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
641
642	includeDir := filepath.Join(snapshotArchDir, "include")
643	configsDir := filepath.Join(snapshotArchDir, "configs")
644	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
645
646	installedNotices := make(map[string]bool)
647	installedConfigs := make(map[string]bool)
648
649	var headers android.Paths
650
651	installSnapshot := func(m *Module) android.Paths {
652		targetArch := "arch-" + m.Target().Arch.ArchType.String()
653		if m.Target().Arch.ArchVariant != "" {
654			targetArch += "-" + m.Target().Arch.ArchVariant
655		}
656
657		var ret android.Paths
658
659		prop := struct {
660			ModuleName          string `json:",omitempty"`
661			RelativeInstallPath string `json:",omitempty"`
662
663			// library flags
664			ExportedDirs       []string `json:",omitempty"`
665			ExportedSystemDirs []string `json:",omitempty"`
666			ExportedFlags      []string `json:",omitempty"`
667			SanitizeMinimalDep bool     `json:",omitempty"`
668			SanitizeUbsanDep   bool     `json:",omitempty"`
669
670			// binary flags
671			Symlinks []string `json:",omitempty"`
672
673			// dependencies
674			SharedLibs  []string `json:",omitempty"`
675			RuntimeLibs []string `json:",omitempty"`
676			Required    []string `json:",omitempty"`
677
678			// extra config files
679			InitRc         []string `json:",omitempty"`
680			VintfFragments []string `json:",omitempty"`
681		}{}
682
683		// Common properties among snapshots.
684		prop.ModuleName = ctx.ModuleName(m)
685		if m.isVndkExt() {
686			// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
687			if m.isVndkSp() {
688				prop.RelativeInstallPath = "vndk-sp"
689			} else {
690				prop.RelativeInstallPath = "vndk"
691			}
692		} else {
693			prop.RelativeInstallPath = m.RelativeInstallPath()
694		}
695		prop.RuntimeLibs = m.Properties.SnapshotRuntimeLibs
696		prop.Required = m.RequiredModuleNames()
697		for _, path := range m.InitRc() {
698			prop.InitRc = append(prop.InitRc, filepath.Join("configs", path.Base()))
699		}
700		for _, path := range m.VintfFragments() {
701			prop.VintfFragments = append(prop.VintfFragments, filepath.Join("configs", path.Base()))
702		}
703
704		// install config files. ignores any duplicates.
705		for _, path := range append(m.InitRc(), m.VintfFragments()...) {
706			out := filepath.Join(configsDir, path.Base())
707			if !installedConfigs[out] {
708				installedConfigs[out] = true
709				ret = append(ret, copyFile(ctx, path, out))
710			}
711		}
712
713		var propOut string
714
715		if l, ok := m.linker.(snapshotLibraryInterface); ok {
716			// library flags
717			prop.ExportedFlags = l.exportedFlags()
718			for _, dir := range l.exportedDirs() {
719				prop.ExportedDirs = append(prop.ExportedDirs, filepath.Join("include", dir.String()))
720			}
721			for _, dir := range l.exportedSystemDirs() {
722				prop.ExportedSystemDirs = append(prop.ExportedSystemDirs, filepath.Join("include", dir.String()))
723			}
724			// shared libs dependencies aren't meaningful on static or header libs
725			if l.shared() {
726				prop.SharedLibs = m.Properties.SnapshotSharedLibs
727			}
728			if l.static() && m.sanitize != nil {
729				prop.SanitizeMinimalDep = m.sanitize.Properties.MinimalRuntimeDep || enableMinimalRuntime(m.sanitize)
730				prop.SanitizeUbsanDep = m.sanitize.Properties.UbsanRuntimeDep || enableUbsanRuntime(m.sanitize)
731			}
732
733			var libType string
734			if l.static() {
735				libType = "static"
736			} else if l.shared() {
737				libType = "shared"
738			} else {
739				libType = "header"
740			}
741
742			var stem string
743
744			// install .a or .so
745			if libType != "header" {
746				libPath := m.outputFile.Path()
747				stem = libPath.Base()
748				snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
749				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
750			} else {
751				stem = ctx.ModuleName(m)
752			}
753
754			propOut = filepath.Join(snapshotArchDir, targetArch, libType, stem+".json")
755		} else if m.binary() {
756			// binary flags
757			prop.Symlinks = m.Symlinks()
758			prop.SharedLibs = m.Properties.SnapshotSharedLibs
759
760			// install bin
761			binPath := m.outputFile.Path()
762			snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
763			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut))
764			propOut = snapshotBinOut + ".json"
765		} else if m.object() {
766			// object files aren't installed to the device, so their names can conflict.
767			// Use module name as stem.
768			objPath := m.outputFile.Path()
769			snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
770				ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
771			ret = append(ret, copyFile(ctx, objPath, snapshotObjOut))
772			propOut = snapshotObjOut + ".json"
773		} else {
774			ctx.Errorf("unknown module %q in vendor snapshot", m.String())
775			return nil
776		}
777
778		j, err := json.Marshal(prop)
779		if err != nil {
780			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
781			return nil
782		}
783		ret = append(ret, writeStringToFile(ctx, string(j), propOut))
784
785		return ret
786	}
787
788	ctx.VisitAllModules(func(module android.Module) {
789		m, ok := module.(*Module)
790		if !ok {
791			return
792		}
793
794		moduleDir := ctx.ModuleDir(module)
795		if !isVendorSnapshotModule(m, moduleDir) {
796			return
797		}
798
799		snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...)
800		if l, ok := m.linker.(snapshotLibraryInterface); ok {
801			headers = append(headers, l.snapshotHeaders()...)
802		}
803
804		if len(m.NoticeFiles()) > 0 {
805			noticeName := ctx.ModuleName(m) + ".txt"
806			noticeOut := filepath.Join(noticeDir, noticeName)
807			// skip already copied notice file
808			if !installedNotices[noticeOut] {
809				installedNotices[noticeOut] = true
810				snapshotOutputs = append(snapshotOutputs, combineNotices(
811					ctx, m.NoticeFiles(), noticeOut))
812			}
813		}
814	})
815
816	// install all headers after removing duplicates
817	for _, header := range android.FirstUniquePaths(headers) {
818		snapshotOutputs = append(snapshotOutputs, copyFile(
819			ctx, header, filepath.Join(includeDir, header.String())))
820	}
821
822	// All artifacts are ready. Sort them to normalize ninja and then zip.
823	sort.Slice(snapshotOutputs, func(i, j int) bool {
824		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
825	})
826
827	zipPath := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+".zip")
828	zipRule := android.NewRuleBuilder()
829
830	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
831	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+"_list")
832	zipRule.Command().
833		Text("tr").
834		FlagWithArg("-d ", "\\'").
835		FlagWithRspFileInputList("< ", snapshotOutputs).
836		FlagWithOutput("> ", snapshotOutputList)
837
838	zipRule.Temporary(snapshotOutputList)
839
840	zipRule.Command().
841		BuiltTool(ctx, "soong_zip").
842		FlagWithOutput("-o ", zipPath).
843		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
844		FlagWithInput("-l ", snapshotOutputList)
845
846	zipRule.Build(pctx, ctx, zipPath.String(), "vendor snapshot "+zipPath.String())
847	zipRule.DeleteTemporaryFiles()
848	c.vendorSnapshotZipFile = android.OptionalPathForPath(zipPath)
849}
850
851func (c *vendorSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
852	ctx.Strict("SOONG_VENDOR_SNAPSHOT_ZIP", c.vendorSnapshotZipFile.String())
853}
854
855type snapshotInterface interface {
856	matchesWithDevice(config android.DeviceConfig) bool
857}
858
859var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
860var _ snapshotInterface = (*vendorSnapshotLibraryDecorator)(nil)
861var _ snapshotInterface = (*vendorSnapshotBinaryDecorator)(nil)
862var _ snapshotInterface = (*vendorSnapshotObjectLinker)(nil)
863
864// gathers all snapshot modules for vendor, and disable unnecessary snapshots
865// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules
866func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) {
867	vndkVersion := ctx.DeviceConfig().VndkVersion()
868	// don't need snapshot if current
869	if vndkVersion == "current" || vndkVersion == "" {
870		return
871	}
872
873	module, ok := ctx.Module().(*Module)
874	if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion {
875		return
876	}
877
878	if !module.isSnapshotPrebuilt() {
879		return
880	}
881
882	// isSnapshotPrebuilt ensures snapshotInterface
883	if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) {
884		// Disable unnecessary snapshot module, but do not disable
885		// vndk_prebuilt_shared because they might be packed into vndk APEX
886		if !module.IsVndk() {
887			module.Disable()
888		}
889		return
890	}
891
892	var snapshotMap *snapshotMap
893
894	if lib, ok := module.linker.(libraryInterface); ok {
895		if lib.static() {
896			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
897		} else if lib.shared() {
898			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
899		} else {
900			// header
901			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
902		}
903	} else if _, ok := module.linker.(*vendorSnapshotBinaryDecorator); ok {
904		snapshotMap = vendorSnapshotBinaries(ctx.Config())
905	} else if _, ok := module.linker.(*vendorSnapshotObjectLinker); ok {
906		snapshotMap = vendorSnapshotObjects(ctx.Config())
907	} else {
908		return
909	}
910
911	vendorSnapshotsLock.Lock()
912	defer vendorSnapshotsLock.Unlock()
913	snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName())
914}
915
916// Disables source modules which have snapshots
917func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
918	if !ctx.Device() {
919		return
920	}
921
922	vndkVersion := ctx.DeviceConfig().VndkVersion()
923	// don't need snapshot if current
924	if vndkVersion == "current" || vndkVersion == "" {
925		return
926	}
927
928	module, ok := ctx.Module().(*Module)
929	if !ok {
930		return
931	}
932
933	// vendor suffix should be added to snapshots if the source module isn't vendor: true.
934	if !module.SocSpecific() {
935		// But we can't just check SocSpecific() since we already passed the image mutator.
936		// Check ramdisk and recovery to see if we are real "vendor: true" module.
937		ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
938		recovery_available := module.InRecovery() && !module.OnlyInRecovery()
939
940		if !ramdisk_available && !recovery_available {
941			vendorSnapshotsLock.Lock()
942			defer vendorSnapshotsLock.Unlock()
943
944			vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
945		}
946	}
947
948	if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() {
949		// only non-snapshot modules with BOARD_VNDK_VERSION
950		return
951	}
952
953	// .. and also filter out llndk library
954	if module.isLlndk(ctx.Config()) {
955		return
956	}
957
958	var snapshotMap *snapshotMap
959
960	if lib, ok := module.linker.(libraryInterface); ok {
961		if lib.static() {
962			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
963		} else if lib.shared() {
964			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
965		} else {
966			// header
967			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
968		}
969	} else if module.binary() {
970		snapshotMap = vendorSnapshotBinaries(ctx.Config())
971	} else if module.object() {
972		snapshotMap = vendorSnapshotObjects(ctx.Config())
973	} else {
974		return
975	}
976
977	if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok {
978		// Corresponding snapshot doesn't exist
979		return
980	}
981
982	// Disables source modules if corresponding snapshot exists.
983	if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() {
984		// But do not disable because the shared variant depends on the static variant.
985		module.SkipInstall()
986		module.Properties.HideFromMake = true
987	} else {
988		module.Disable()
989	}
990}
991