• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
556	// Libraries
557	if l, ok := m.linker.(snapshotLibraryInterface); ok {
558		// TODO(b/65377115): add full support for sanitizer
559		if m.sanitize != nil {
560			// cfi, scs and hwasan export both sanitized and unsanitized variants for static and header
561			// Always use unsanitized variants of them.
562			for _, t := range []sanitizerType{cfi, scs, hwasan} {
563				if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
564					return false
565				}
566			}
567		}
568		if l.static() {
569			return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
570		}
571		if l.shared() {
572			if !m.outputFile.Valid() {
573				return false
574			}
575			if !m.IsVndk() {
576				return true
577			}
578			return m.isVndkExt()
579		}
580		return true
581	}
582
583	// Binaries and Objects
584	if m.binary() || m.object() {
585		return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
586	}
587
588	return false
589}
590
591func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
592	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a vendor snapshot.
593	if ctx.DeviceConfig().VndkVersion() != "current" {
594		return
595	}
596
597	var snapshotOutputs android.Paths
598
599	/*
600		Vendor snapshot zipped artifacts directory structure:
601		{SNAPSHOT_ARCH}/
602			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
603				shared/
604					(.so shared libraries)
605				static/
606					(.a static libraries)
607				header/
608					(header only libraries)
609				binary/
610					(executable binaries)
611				object/
612					(.o object files)
613			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
614				shared/
615					(.so shared libraries)
616				static/
617					(.a static libraries)
618				header/
619					(header only libraries)
620				binary/
621					(executable binaries)
622				object/
623					(.o object files)
624			NOTICE_FILES/
625				(notice files, e.g. libbase.txt)
626			configs/
627				(config files, e.g. init.rc files, vintf_fragments.xml files, etc.)
628			include/
629				(header files of same directory structure with source tree)
630	*/
631
632	snapshotDir := "vendor-snapshot"
633	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
634
635	includeDir := filepath.Join(snapshotArchDir, "include")
636	configsDir := filepath.Join(snapshotArchDir, "configs")
637	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
638
639	installedNotices := make(map[string]bool)
640	installedConfigs := make(map[string]bool)
641
642	var headers android.Paths
643
644	installSnapshot := func(m *Module) android.Paths {
645		targetArch := "arch-" + m.Target().Arch.ArchType.String()
646		if m.Target().Arch.ArchVariant != "" {
647			targetArch += "-" + m.Target().Arch.ArchVariant
648		}
649
650		var ret android.Paths
651
652		prop := struct {
653			ModuleName          string `json:",omitempty"`
654			RelativeInstallPath string `json:",omitempty"`
655
656			// library flags
657			ExportedDirs       []string `json:",omitempty"`
658			ExportedSystemDirs []string `json:",omitempty"`
659			ExportedFlags      []string `json:",omitempty"`
660			SanitizeMinimalDep bool     `json:",omitempty"`
661			SanitizeUbsanDep   bool     `json:",omitempty"`
662
663			// binary flags
664			Symlinks []string `json:",omitempty"`
665
666			// dependencies
667			SharedLibs  []string `json:",omitempty"`
668			RuntimeLibs []string `json:",omitempty"`
669			Required    []string `json:",omitempty"`
670
671			// extra config files
672			InitRc         []string `json:",omitempty"`
673			VintfFragments []string `json:",omitempty"`
674		}{}
675
676		// Common properties among snapshots.
677		prop.ModuleName = ctx.ModuleName(m)
678		if m.isVndkExt() {
679			// vndk exts are installed to /vendor/lib(64)?/vndk(-sp)?
680			if m.isVndkSp() {
681				prop.RelativeInstallPath = "vndk-sp"
682			} else {
683				prop.RelativeInstallPath = "vndk"
684			}
685		} else {
686			prop.RelativeInstallPath = m.RelativeInstallPath()
687		}
688		prop.RuntimeLibs = m.Properties.SnapshotRuntimeLibs
689		prop.Required = m.RequiredModuleNames()
690		for _, path := range m.InitRc() {
691			prop.InitRc = append(prop.InitRc, filepath.Join("configs", path.Base()))
692		}
693		for _, path := range m.VintfFragments() {
694			prop.VintfFragments = append(prop.VintfFragments, filepath.Join("configs", path.Base()))
695		}
696
697		// install config files. ignores any duplicates.
698		for _, path := range append(m.InitRc(), m.VintfFragments()...) {
699			out := filepath.Join(configsDir, path.Base())
700			if !installedConfigs[out] {
701				installedConfigs[out] = true
702				ret = append(ret, copyFile(ctx, path, out))
703			}
704		}
705
706		var propOut string
707
708		if l, ok := m.linker.(snapshotLibraryInterface); ok {
709			// library flags
710			prop.ExportedFlags = l.exportedFlags()
711			for _, dir := range l.exportedDirs() {
712				prop.ExportedDirs = append(prop.ExportedDirs, filepath.Join("include", dir.String()))
713			}
714			for _, dir := range l.exportedSystemDirs() {
715				prop.ExportedSystemDirs = append(prop.ExportedSystemDirs, filepath.Join("include", dir.String()))
716			}
717			// shared libs dependencies aren't meaningful on static or header libs
718			if l.shared() {
719				prop.SharedLibs = m.Properties.SnapshotSharedLibs
720			}
721			if l.static() && m.sanitize != nil {
722				prop.SanitizeMinimalDep = m.sanitize.Properties.MinimalRuntimeDep || enableMinimalRuntime(m.sanitize)
723				prop.SanitizeUbsanDep = m.sanitize.Properties.UbsanRuntimeDep || enableUbsanRuntime(m.sanitize)
724			}
725
726			var libType string
727			if l.static() {
728				libType = "static"
729			} else if l.shared() {
730				libType = "shared"
731			} else {
732				libType = "header"
733			}
734
735			var stem string
736
737			// install .a or .so
738			if libType != "header" {
739				libPath := m.outputFile.Path()
740				stem = libPath.Base()
741				snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
742				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
743			} else {
744				stem = ctx.ModuleName(m)
745			}
746
747			propOut = filepath.Join(snapshotArchDir, targetArch, libType, stem+".json")
748		} else if m.binary() {
749			// binary flags
750			prop.Symlinks = m.Symlinks()
751			prop.SharedLibs = m.Properties.SnapshotSharedLibs
752
753			// install bin
754			binPath := m.outputFile.Path()
755			snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
756			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut))
757			propOut = snapshotBinOut + ".json"
758		} else if m.object() {
759			// object files aren't installed to the device, so their names can conflict.
760			// Use module name as stem.
761			objPath := m.outputFile.Path()
762			snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
763				ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
764			ret = append(ret, copyFile(ctx, objPath, snapshotObjOut))
765			propOut = snapshotObjOut + ".json"
766		} else {
767			ctx.Errorf("unknown module %q in vendor snapshot", m.String())
768			return nil
769		}
770
771		j, err := json.Marshal(prop)
772		if err != nil {
773			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
774			return nil
775		}
776		ret = append(ret, writeStringToFile(ctx, string(j), propOut))
777
778		return ret
779	}
780
781	ctx.VisitAllModules(func(module android.Module) {
782		m, ok := module.(*Module)
783		if !ok {
784			return
785		}
786
787		moduleDir := ctx.ModuleDir(module)
788		if !isVendorSnapshotModule(m, moduleDir) {
789			return
790		}
791
792		snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...)
793		if l, ok := m.linker.(snapshotLibraryInterface); ok {
794			headers = append(headers, l.snapshotHeaders()...)
795		}
796
797		if m.NoticeFile().Valid() {
798			noticeName := ctx.ModuleName(m) + ".txt"
799			noticeOut := filepath.Join(noticeDir, noticeName)
800			// skip already copied notice file
801			if !installedNotices[noticeOut] {
802				installedNotices[noticeOut] = true
803				snapshotOutputs = append(snapshotOutputs, copyFile(
804					ctx, m.NoticeFile().Path(), noticeOut))
805			}
806		}
807	})
808
809	// install all headers after removing duplicates
810	for _, header := range android.FirstUniquePaths(headers) {
811		snapshotOutputs = append(snapshotOutputs, copyFile(
812			ctx, header, filepath.Join(includeDir, header.String())))
813	}
814
815	// All artifacts are ready. Sort them to normalize ninja and then zip.
816	sort.Slice(snapshotOutputs, func(i, j int) bool {
817		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
818	})
819
820	zipPath := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+".zip")
821	zipRule := android.NewRuleBuilder()
822
823	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
824	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "vendor-"+ctx.Config().DeviceName()+"_list")
825	zipRule.Command().
826		Text("tr").
827		FlagWithArg("-d ", "\\'").
828		FlagWithRspFileInputList("< ", snapshotOutputs).
829		FlagWithOutput("> ", snapshotOutputList)
830
831	zipRule.Temporary(snapshotOutputList)
832
833	zipRule.Command().
834		BuiltTool(ctx, "soong_zip").
835		FlagWithOutput("-o ", zipPath).
836		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
837		FlagWithInput("-l ", snapshotOutputList)
838
839	zipRule.Build(pctx, ctx, zipPath.String(), "vendor snapshot "+zipPath.String())
840	zipRule.DeleteTemporaryFiles()
841	c.vendorSnapshotZipFile = android.OptionalPathForPath(zipPath)
842}
843
844func (c *vendorSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
845	ctx.Strict("SOONG_VENDOR_SNAPSHOT_ZIP", c.vendorSnapshotZipFile.String())
846}
847
848type snapshotInterface interface {
849	matchesWithDevice(config android.DeviceConfig) bool
850}
851
852var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
853var _ snapshotInterface = (*vendorSnapshotLibraryDecorator)(nil)
854var _ snapshotInterface = (*vendorSnapshotBinaryDecorator)(nil)
855var _ snapshotInterface = (*vendorSnapshotObjectLinker)(nil)
856
857// gathers all snapshot modules for vendor, and disable unnecessary snapshots
858// TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules
859func VendorSnapshotMutator(ctx android.BottomUpMutatorContext) {
860	vndkVersion := ctx.DeviceConfig().VndkVersion()
861	// don't need snapshot if current
862	if vndkVersion == "current" || vndkVersion == "" {
863		return
864	}
865
866	module, ok := ctx.Module().(*Module)
867	if !ok || !module.Enabled() || module.VndkVersion() != vndkVersion {
868		return
869	}
870
871	if !module.isSnapshotPrebuilt() {
872		return
873	}
874
875	// isSnapshotPrebuilt ensures snapshotInterface
876	if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) {
877		// Disable unnecessary snapshot module, but do not disable
878		// vndk_prebuilt_shared because they might be packed into vndk APEX
879		if !module.IsVndk() {
880			module.Disable()
881		}
882		return
883	}
884
885	var snapshotMap *snapshotMap
886
887	if lib, ok := module.linker.(libraryInterface); ok {
888		if lib.static() {
889			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
890		} else if lib.shared() {
891			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
892		} else {
893			// header
894			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
895		}
896	} else if _, ok := module.linker.(*vendorSnapshotBinaryDecorator); ok {
897		snapshotMap = vendorSnapshotBinaries(ctx.Config())
898	} else if _, ok := module.linker.(*vendorSnapshotObjectLinker); ok {
899		snapshotMap = vendorSnapshotObjects(ctx.Config())
900	} else {
901		return
902	}
903
904	vendorSnapshotsLock.Lock()
905	defer vendorSnapshotsLock.Unlock()
906	snapshotMap.add(module.BaseModuleName(), ctx.Arch().ArchType, ctx.ModuleName())
907}
908
909// Disables source modules which have snapshots
910func VendorSnapshotSourceMutator(ctx android.BottomUpMutatorContext) {
911	if !ctx.Device() {
912		return
913	}
914
915	vndkVersion := ctx.DeviceConfig().VndkVersion()
916	// don't need snapshot if current
917	if vndkVersion == "current" || vndkVersion == "" {
918		return
919	}
920
921	module, ok := ctx.Module().(*Module)
922	if !ok {
923		return
924	}
925
926	// vendor suffix should be added to snapshots if the source module isn't vendor: true.
927	if !module.SocSpecific() {
928		// But we can't just check SocSpecific() since we already passed the image mutator.
929		// Check ramdisk and recovery to see if we are real "vendor: true" module.
930		ramdisk_available := module.InRamdisk() && !module.OnlyInRamdisk()
931		recovery_available := module.InRecovery() && !module.OnlyInRecovery()
932
933		if !ramdisk_available && !recovery_available {
934			vendorSnapshotsLock.Lock()
935			defer vendorSnapshotsLock.Unlock()
936
937			vendorSuffixModules(ctx.Config())[ctx.ModuleName()] = true
938		}
939	}
940
941	if module.isSnapshotPrebuilt() || module.VndkVersion() != ctx.DeviceConfig().VndkVersion() {
942		// only non-snapshot modules with BOARD_VNDK_VERSION
943		return
944	}
945
946	// .. and also filter out llndk library
947	if module.isLlndk(ctx.Config()) {
948		return
949	}
950
951	var snapshotMap *snapshotMap
952
953	if lib, ok := module.linker.(libraryInterface); ok {
954		if lib.static() {
955			snapshotMap = vendorSnapshotStaticLibs(ctx.Config())
956		} else if lib.shared() {
957			snapshotMap = vendorSnapshotSharedLibs(ctx.Config())
958		} else {
959			// header
960			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
961		}
962	} else if module.binary() {
963		snapshotMap = vendorSnapshotBinaries(ctx.Config())
964	} else if module.object() {
965		snapshotMap = vendorSnapshotObjects(ctx.Config())
966	} else {
967		return
968	}
969
970	if _, ok := snapshotMap.get(ctx.ModuleName(), ctx.Arch().ArchType); !ok {
971		// Corresponding snapshot doesn't exist
972		return
973	}
974
975	// Disables source modules if corresponding snapshot exists.
976	if lib, ok := module.linker.(libraryInterface); ok && lib.buildStatic() && lib.buildShared() {
977		// But do not disable because the shared variant depends on the static variant.
978		module.SkipInstall()
979		module.Properties.HideFromMake = true
980	} else {
981		module.Disable()
982	}
983}
984