1// Copyright 2017 Google Inc. All rights reserved.
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.
14
15package cc
16
17import (
18	"encoding/json"
19	"errors"
20	"fmt"
21	"path/filepath"
22	"sort"
23	"strings"
24	"sync"
25
26	"android/soong/android"
27	"android/soong/cc/config"
28	"android/soong/etc"
29)
30
31const (
32	llndkLibrariesTxt                = "llndk.libraries.txt"
33	vndkCoreLibrariesTxt             = "vndkcore.libraries.txt"
34	vndkSpLibrariesTxt               = "vndksp.libraries.txt"
35	vndkPrivateLibrariesTxt          = "vndkprivate.libraries.txt"
36	vndkUsingCoreVariantLibrariesTxt = "vndkcorevariant.libraries.txt"
37)
38
39func VndkLibrariesTxtModules(vndkVersion string) []string {
40	if vndkVersion == "current" {
41		return []string{
42			llndkLibrariesTxt,
43			vndkCoreLibrariesTxt,
44			vndkSpLibrariesTxt,
45			vndkPrivateLibrariesTxt,
46		}
47	}
48	// Snapshot vndks have their own *.libraries.VER.txt files.
49	// Note that snapshots don't have "vndkcorevariant.libraries.VER.txt"
50	return []string{
51		insertVndkVersion(llndkLibrariesTxt, vndkVersion),
52		insertVndkVersion(vndkCoreLibrariesTxt, vndkVersion),
53		insertVndkVersion(vndkSpLibrariesTxt, vndkVersion),
54		insertVndkVersion(vndkPrivateLibrariesTxt, vndkVersion),
55	}
56}
57
58type VndkProperties struct {
59	Vndk struct {
60		// declared as a VNDK or VNDK-SP module. The vendor variant
61		// will be installed in /system instead of /vendor partition.
62		//
63		// `vendor_available` must be explicitly set to either true or
64		// false together with `vndk: {enabled: true}`.
65		Enabled *bool
66
67		// declared as a VNDK-SP module, which is a subset of VNDK.
68		//
69		// `vndk: { enabled: true }` must set together.
70		//
71		// All these modules are allowed to link to VNDK-SP or LL-NDK
72		// modules only. Other dependency will cause link-type errors.
73		//
74		// If `support_system_process` is not set or set to false,
75		// the module is VNDK-core and can link to other VNDK-core,
76		// VNDK-SP or LL-NDK modules only.
77		Support_system_process *bool
78
79		// Extending another module
80		Extends *string
81	}
82}
83
84type vndkdep struct {
85	Properties VndkProperties
86}
87
88func (vndk *vndkdep) props() []interface{} {
89	return []interface{}{&vndk.Properties}
90}
91
92func (vndk *vndkdep) begin(ctx BaseModuleContext) {}
93
94func (vndk *vndkdep) deps(ctx BaseModuleContext, deps Deps) Deps {
95	return deps
96}
97
98func (vndk *vndkdep) isVndk() bool {
99	return Bool(vndk.Properties.Vndk.Enabled)
100}
101
102func (vndk *vndkdep) isVndkSp() bool {
103	return Bool(vndk.Properties.Vndk.Support_system_process)
104}
105
106func (vndk *vndkdep) isVndkExt() bool {
107	return vndk.Properties.Vndk.Extends != nil
108}
109
110func (vndk *vndkdep) getVndkExtendsModuleName() string {
111	return String(vndk.Properties.Vndk.Extends)
112}
113
114func (vndk *vndkdep) typeName() string {
115	if !vndk.isVndk() {
116		return "native:vendor"
117	}
118	if !vndk.isVndkExt() {
119		if !vndk.isVndkSp() {
120			return "native:vendor:vndk"
121		}
122		return "native:vendor:vndksp"
123	}
124	if !vndk.isVndkSp() {
125		return "native:vendor:vndkext"
126	}
127	return "native:vendor:vndkspext"
128}
129
130func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag DependencyTag) {
131	if to.linker == nil {
132		return
133	}
134	if !vndk.isVndk() {
135		// Non-VNDK modules (those installed to /vendor, /product, or /system/product) can't depend
136		// on modules marked with vendor_available: false.
137		violation := false
138		if lib, ok := to.linker.(*llndkStubDecorator); ok && !Bool(lib.Properties.Vendor_available) {
139			violation = true
140		} else {
141			if _, ok := to.linker.(libraryInterface); ok && to.VendorProperties.Vendor_available != nil && !Bool(to.VendorProperties.Vendor_available) {
142				// Vendor_available == nil && !Bool(Vendor_available) should be okay since
143				// it means a vendor-only, or product-only library which is a valid dependency
144				// for non-VNDK modules.
145				violation = true
146			}
147		}
148		if violation {
149			ctx.ModuleErrorf("Vendor module that is not VNDK should not link to %q which is marked as `vendor_available: false`", to.Name())
150		}
151	}
152	if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() {
153		// Check only shared libraries.
154		// Other (static and LL-NDK) libraries are allowed to link.
155		return
156	}
157	if !to.UseVndk() {
158		ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library",
159			vndk.typeName(), to.Name())
160		return
161	}
162	if tag == vndkExtDepTag {
163		// Ensure `extends: "name"` property refers a vndk module that has vendor_available
164		// and has identical vndk properties.
165		if to.vndkdep == nil || !to.vndkdep.isVndk() {
166			ctx.ModuleErrorf("`extends` refers a non-vndk module %q", to.Name())
167			return
168		}
169		if vndk.isVndkSp() != to.vndkdep.isVndkSp() {
170			ctx.ModuleErrorf(
171				"`extends` refers a module %q with mismatched support_system_process",
172				to.Name())
173			return
174		}
175		if !Bool(to.VendorProperties.Vendor_available) {
176			ctx.ModuleErrorf(
177				"`extends` refers module %q which does not have `vendor_available: true`",
178				to.Name())
179			return
180		}
181	}
182	if to.vndkdep == nil {
183		return
184	}
185
186	// Check the dependencies of VNDK shared libraries.
187	if err := vndkIsVndkDepAllowed(vndk, to.vndkdep); err != nil {
188		ctx.ModuleErrorf("(%s) should not link to %q (%s): %v",
189			vndk.typeName(), to.Name(), to.vndkdep.typeName(), err)
190		return
191	}
192}
193
194func vndkIsVndkDepAllowed(from *vndkdep, to *vndkdep) error {
195	// Check the dependencies of VNDK, VNDK-Ext, VNDK-SP, VNDK-SP-Ext and vendor modules.
196	if from.isVndkExt() {
197		if from.isVndkSp() {
198			if to.isVndk() && !to.isVndkSp() {
199				return errors.New("VNDK-SP extensions must not depend on VNDK or VNDK extensions")
200			}
201			return nil
202		}
203		// VNDK-Ext may depend on VNDK, VNDK-Ext, VNDK-SP, VNDK-SP-Ext, or vendor libs.
204		return nil
205	}
206	if from.isVndk() {
207		if to.isVndkExt() {
208			return errors.New("VNDK-core and VNDK-SP must not depend on VNDK extensions")
209		}
210		if from.isVndkSp() {
211			if !to.isVndkSp() {
212				return errors.New("VNDK-SP must only depend on VNDK-SP")
213			}
214			return nil
215		}
216		if !to.isVndk() {
217			return errors.New("VNDK-core must only depend on VNDK-core or VNDK-SP")
218		}
219		return nil
220	}
221	// Vendor modules may depend on VNDK, VNDK-Ext, VNDK-SP, VNDK-SP-Ext, or vendor libs.
222	return nil
223}
224
225var (
226	vndkCoreLibrariesKey             = android.NewOnceKey("vndkCoreLibrarires")
227	vndkSpLibrariesKey               = android.NewOnceKey("vndkSpLibrarires")
228	llndkLibrariesKey                = android.NewOnceKey("llndkLibrarires")
229	vndkPrivateLibrariesKey          = android.NewOnceKey("vndkPrivateLibrarires")
230	vndkUsingCoreVariantLibrariesKey = android.NewOnceKey("vndkUsingCoreVariantLibraries")
231	vndkMustUseVendorVariantListKey  = android.NewOnceKey("vndkMustUseVendorVariantListKey")
232	vndkLibrariesLock                sync.Mutex
233)
234
235func vndkCoreLibraries(config android.Config) map[string]string {
236	return config.Once(vndkCoreLibrariesKey, func() interface{} {
237		return make(map[string]string)
238	}).(map[string]string)
239}
240
241func vndkSpLibraries(config android.Config) map[string]string {
242	return config.Once(vndkSpLibrariesKey, func() interface{} {
243		return make(map[string]string)
244	}).(map[string]string)
245}
246
247func isLlndkLibrary(baseModuleName string, config android.Config) bool {
248	_, ok := llndkLibraries(config)[baseModuleName]
249	return ok
250}
251
252func llndkLibraries(config android.Config) map[string]string {
253	return config.Once(llndkLibrariesKey, func() interface{} {
254		return make(map[string]string)
255	}).(map[string]string)
256}
257
258func isVndkPrivateLibrary(baseModuleName string, config android.Config) bool {
259	_, ok := vndkPrivateLibraries(config)[baseModuleName]
260	return ok
261}
262
263func vndkPrivateLibraries(config android.Config) map[string]string {
264	return config.Once(vndkPrivateLibrariesKey, func() interface{} {
265		return make(map[string]string)
266	}).(map[string]string)
267}
268
269func vndkUsingCoreVariantLibraries(config android.Config) map[string]string {
270	return config.Once(vndkUsingCoreVariantLibrariesKey, func() interface{} {
271		return make(map[string]string)
272	}).(map[string]string)
273}
274
275func vndkMustUseVendorVariantList(cfg android.Config) []string {
276	return cfg.Once(vndkMustUseVendorVariantListKey, func() interface{} {
277		return config.VndkMustUseVendorVariantList
278	}).([]string)
279}
280
281// test may call this to override global configuration(config.VndkMustUseVendorVariantList)
282// when it is called, it must be before the first call to vndkMustUseVendorVariantList()
283func setVndkMustUseVendorVariantListForTest(config android.Config, mustUseVendorVariantList []string) {
284	config.Once(vndkMustUseVendorVariantListKey, func() interface{} {
285		return mustUseVendorVariantList
286	})
287}
288
289func processLlndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
290	lib := m.linker.(*llndkStubDecorator)
291	name := m.BaseModuleName()
292	filename := m.BaseModuleName() + ".so"
293
294	vndkLibrariesLock.Lock()
295	defer vndkLibrariesLock.Unlock()
296
297	llndkLibraries(mctx.Config())[name] = filename
298	if !Bool(lib.Properties.Vendor_available) {
299		vndkPrivateLibraries(mctx.Config())[name] = filename
300	}
301	if mctx.OtherModuleExists(name) {
302		mctx.AddFarVariationDependencies(m.Target().Variations(), llndkImplDep, name)
303	}
304}
305
306func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
307	name := m.BaseModuleName()
308	filename, err := getVndkFileName(m)
309	if err != nil {
310		panic(err)
311	}
312
313	if m.HasStubsVariants() && name != "libz" {
314		// b/155456180 libz is the ONLY exception here. We don't want to make
315		// libz an LLNDK library because we in general can't guarantee that
316		// libz will behave consistently especially about the compression.
317		// i.e. the compressed output might be different across releases.
318		// As the library is an external one, it's risky to keep the compatibility
319		// promise if it becomes an LLNDK.
320		mctx.PropertyErrorf("vndk.enabled", "This library provides stubs. Shouldn't be VNDK. Consider making it as LLNDK")
321	}
322
323	vndkLibrariesLock.Lock()
324	defer vndkLibrariesLock.Unlock()
325
326	if inList(name, vndkMustUseVendorVariantList(mctx.Config())) {
327		m.Properties.MustUseVendorVariant = true
328	}
329	if mctx.DeviceConfig().VndkUseCoreVariant() && !m.Properties.MustUseVendorVariant {
330		vndkUsingCoreVariantLibraries(mctx.Config())[name] = filename
331	}
332
333	if m.vndkdep.isVndkSp() {
334		vndkSpLibraries(mctx.Config())[name] = filename
335	} else {
336		vndkCoreLibraries(mctx.Config())[name] = filename
337	}
338	if !Bool(m.VendorProperties.Vendor_available) {
339		vndkPrivateLibraries(mctx.Config())[name] = filename
340	}
341}
342
343// Check for modules that mustn't be VNDK
344func shouldSkipVndkMutator(m *Module) bool {
345	if !m.Enabled() {
346		return true
347	}
348	if !m.Device() {
349		// Skip non-device modules
350		return true
351	}
352	if m.Target().NativeBridge == android.NativeBridgeEnabled {
353		// Skip native_bridge modules
354		return true
355	}
356	return false
357}
358
359func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool {
360	if shouldSkipVndkMutator(m) {
361		return false
362	}
363
364	// prebuilt vndk modules should match with device
365	// TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared
366	// When b/142675459 is landed, remove following check
367	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.matchesWithDevice(mctx.DeviceConfig()) {
368		return false
369	}
370
371	if lib, ok := m.linker.(libraryInterface); ok {
372		// VNDK APEX for VNDK-Lite devices will have VNDK-SP libraries from core variants
373		if mctx.DeviceConfig().VndkVersion() == "" {
374			// b/73296261: filter out libz.so because it is considered as LLNDK for VNDK-lite devices
375			if mctx.ModuleName() == "libz" {
376				return false
377			}
378			return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.isVndkSp()
379		}
380
381		useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
382			mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
383		return lib.shared() && m.inVendor() && m.IsVndk() && !m.isVndkExt() && !useCoreVariant
384	}
385	return false
386}
387
388// gather list of vndk-core, vndk-sp, and ll-ndk libs
389func VndkMutator(mctx android.BottomUpMutatorContext) {
390	m, ok := mctx.Module().(*Module)
391	if !ok {
392		return
393	}
394
395	if shouldSkipVndkMutator(m) {
396		return
397	}
398
399	if _, ok := m.linker.(*llndkStubDecorator); ok {
400		processLlndkLibrary(mctx, m)
401		return
402	}
403
404	lib, is_lib := m.linker.(*libraryDecorator)
405	prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
406
407	if (is_lib && lib.buildShared()) || (is_prebuilt_lib && prebuilt_lib.buildShared()) {
408		if m.vndkdep != nil && m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
409			processVndkLibrary(mctx, m)
410			return
411		}
412	}
413}
414
415func init() {
416	android.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
417	android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
418}
419
420type vndkLibrariesTxt struct {
421	android.ModuleBase
422	outputFile android.OutputPath
423}
424
425var _ etc.PrebuiltEtcModule = &vndkLibrariesTxt{}
426var _ android.OutputFileProducer = &vndkLibrariesTxt{}
427
428// vndk_libraries_txt is a special kind of module type in that it name is one of
429// - llndk.libraries.txt
430// - vndkcore.libraries.txt
431// - vndksp.libraries.txt
432// - vndkprivate.libraries.txt
433// - vndkcorevariant.libraries.txt
434// A module behaves like a prebuilt_etc but its content is generated by soong.
435// By being a soong module, these files can be referenced by other soong modules.
436// For example, apex_vndk can depend on these files as prebuilt.
437func VndkLibrariesTxtFactory() android.Module {
438	m := &vndkLibrariesTxt{}
439	android.InitAndroidModule(m)
440	return m
441}
442
443func insertVndkVersion(filename string, vndkVersion string) string {
444	if index := strings.LastIndex(filename, "."); index != -1 {
445		return filename[:index] + "." + vndkVersion + filename[index:]
446	}
447	return filename
448}
449
450func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
451	var list []string
452	switch txt.Name() {
453	case llndkLibrariesTxt:
454		for _, filename := range android.SortedStringMapValues(llndkLibraries(ctx.Config())) {
455			if strings.HasPrefix(filename, "libclang_rt.hwasan-") {
456				continue
457			}
458			list = append(list, filename)
459		}
460	case vndkCoreLibrariesTxt:
461		list = android.SortedStringMapValues(vndkCoreLibraries(ctx.Config()))
462	case vndkSpLibrariesTxt:
463		list = android.SortedStringMapValues(vndkSpLibraries(ctx.Config()))
464	case vndkPrivateLibrariesTxt:
465		list = android.SortedStringMapValues(vndkPrivateLibraries(ctx.Config()))
466	case vndkUsingCoreVariantLibrariesTxt:
467		list = android.SortedStringMapValues(vndkUsingCoreVariantLibraries(ctx.Config()))
468	default:
469		ctx.ModuleErrorf("name(%s) is unknown.", txt.Name())
470		return
471	}
472
473	var filename string
474	if txt.Name() != vndkUsingCoreVariantLibrariesTxt {
475		filename = insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion())
476	} else {
477		filename = txt.Name()
478	}
479
480	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
481	ctx.Build(pctx, android.BuildParams{
482		Rule:        android.WriteFile,
483		Output:      txt.outputFile,
484		Description: "Writing " + txt.outputFile.String(),
485		Args: map[string]string{
486			"content": strings.Join(list, "\\n"),
487		},
488	})
489
490	installPath := android.PathForModuleInstall(ctx, "etc")
491	ctx.InstallFile(installPath, filename, txt.outputFile)
492}
493
494func (txt *vndkLibrariesTxt) AndroidMkEntries() []android.AndroidMkEntries {
495	return []android.AndroidMkEntries{android.AndroidMkEntries{
496		Class:      "ETC",
497		OutputFile: android.OptionalPathForPath(txt.outputFile),
498		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
499			func(entries *android.AndroidMkEntries) {
500				entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base())
501			},
502		},
503	}}
504}
505
506func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath {
507	return txt.outputFile
508}
509
510func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
511	return android.Paths{txt.outputFile}, nil
512}
513
514func (txt *vndkLibrariesTxt) SubDir() string {
515	return ""
516}
517
518func VndkSnapshotSingleton() android.Singleton {
519	return &vndkSnapshotSingleton{}
520}
521
522type vndkSnapshotSingleton struct {
523	vndkLibrariesFile   android.OutputPath
524	vndkSnapshotZipFile android.OptionalPath
525}
526
527func isVndkSnapshotLibrary(config android.DeviceConfig, m *Module) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
528	if m.Target().NativeBridge == android.NativeBridgeEnabled {
529		return nil, "", false
530	}
531	if !m.inVendor() || !m.installable() || m.isSnapshotPrebuilt() {
532		return nil, "", false
533	}
534	l, ok := m.linker.(snapshotLibraryInterface)
535	if !ok || !l.shared() {
536		return nil, "", false
537	}
538	if m.VndkVersion() == config.PlatformVndkVersion() && m.IsVndk() && !m.isVndkExt() {
539		if m.isVndkSp() {
540			return l, "vndk-sp", true
541		} else {
542			return l, "vndk-core", true
543		}
544	}
545
546	return nil, "", false
547}
548
549func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
550	// build these files even if PlatformVndkVersion or BoardVndkVersion is not set
551	c.buildVndkLibrariesTxtFiles(ctx)
552
553	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
554	if ctx.DeviceConfig().VndkVersion() != "current" {
555		return
556	}
557
558	if ctx.DeviceConfig().PlatformVndkVersion() == "" {
559		return
560	}
561
562	var snapshotOutputs android.Paths
563
564	/*
565		VNDK snapshot zipped artifacts directory structure:
566		{SNAPSHOT_ARCH}/
567			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
568				shared/
569					vndk-core/
570						(VNDK-core libraries, e.g. libbinder.so)
571					vndk-sp/
572						(VNDK-SP libraries, e.g. libc++.so)
573			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
574				shared/
575					vndk-core/
576						(VNDK-core libraries, e.g. libbinder.so)
577					vndk-sp/
578						(VNDK-SP libraries, e.g. libc++.so)
579			binder32/
580				(This directory is newly introduced in v28 (Android P) to hold
581				prebuilts built for 32-bit binder interface.)
582				arch-{TARGET_ARCH}-{TARGE_ARCH_VARIANT}/
583					...
584			configs/
585				(various *.txt configuration files)
586			include/
587				(header files of same directory structure with source tree)
588			NOTICE_FILES/
589				(notice files of libraries, e.g. libcutils.so.txt)
590	*/
591
592	snapshotDir := "vndk-snapshot"
593	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
594
595	configsDir := filepath.Join(snapshotArchDir, "configs")
596	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
597	includeDir := filepath.Join(snapshotArchDir, "include")
598
599	// set of notice files copied.
600	noticeBuilt := make(map[string]bool)
601
602	// paths of VNDK modules for GPL license checking
603	modulePaths := make(map[string]string)
604
605	// actual module names of .so files
606	// e.g. moduleNames["libprotobuf-cpp-full-3.9.1.so"] = "libprotobuf-cpp-full"
607	moduleNames := make(map[string]string)
608
609	var headers android.Paths
610
611	installVndkSnapshotLib := func(m *Module, l snapshotLibraryInterface, vndkType string) (android.Paths, bool) {
612		var ret android.Paths
613
614		targetArch := "arch-" + m.Target().Arch.ArchType.String()
615		if m.Target().Arch.ArchVariant != "" {
616			targetArch += "-" + m.Target().Arch.ArchVariant
617		}
618
619		libPath := m.outputFile.Path()
620		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
621		ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
622
623		if ctx.Config().VndkSnapshotBuildArtifacts() {
624			prop := struct {
625				ExportedDirs        []string `json:",omitempty"`
626				ExportedSystemDirs  []string `json:",omitempty"`
627				ExportedFlags       []string `json:",omitempty"`
628				RelativeInstallPath string   `json:",omitempty"`
629			}{}
630			prop.ExportedFlags = l.exportedFlags()
631			prop.ExportedDirs = l.exportedDirs().Strings()
632			prop.ExportedSystemDirs = l.exportedSystemDirs().Strings()
633			prop.RelativeInstallPath = m.RelativeInstallPath()
634
635			propOut := snapshotLibOut + ".json"
636
637			j, err := json.Marshal(prop)
638			if err != nil {
639				ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
640				return nil, false
641			}
642			ret = append(ret, writeStringToFile(ctx, string(j), propOut))
643		}
644		return ret, true
645	}
646
647	ctx.VisitAllModules(func(module android.Module) {
648		m, ok := module.(*Module)
649		if !ok || !m.Enabled() {
650			return
651		}
652
653		l, vndkType, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m)
654		if !ok {
655			return
656		}
657
658		// install .so files for appropriate modules.
659		// Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
660		libs, ok := installVndkSnapshotLib(m, l, vndkType)
661		if !ok {
662			return
663		}
664		snapshotOutputs = append(snapshotOutputs, libs...)
665
666		// These are for generating module_names.txt and module_paths.txt
667		stem := m.outputFile.Path().Base()
668		moduleNames[stem] = ctx.ModuleName(m)
669		modulePaths[stem] = ctx.ModuleDir(m)
670
671		if len(m.NoticeFiles()) > 0 {
672			noticeName := stem + ".txt"
673			// skip already copied notice file
674			if _, ok := noticeBuilt[noticeName]; !ok {
675				noticeBuilt[noticeName] = true
676				snapshotOutputs = append(snapshotOutputs, combineNotices(
677					ctx, m.NoticeFiles(), filepath.Join(noticeDir, noticeName)))
678			}
679		}
680
681		if ctx.Config().VndkSnapshotBuildArtifacts() {
682			headers = append(headers, l.snapshotHeaders()...)
683		}
684	})
685
686	// install all headers after removing duplicates
687	for _, header := range android.FirstUniquePaths(headers) {
688		snapshotOutputs = append(snapshotOutputs, copyFile(
689			ctx, header, filepath.Join(includeDir, header.String())))
690	}
691
692	// install *.libraries.txt except vndkcorevariant.libraries.txt
693	ctx.VisitAllModules(func(module android.Module) {
694		m, ok := module.(*vndkLibrariesTxt)
695		if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
696			return
697		}
698		snapshotOutputs = append(snapshotOutputs, copyFile(
699			ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
700	})
701
702	/*
703		Dump a map to a list file as:
704
705		{key1} {value1}
706		{key2} {value2}
707		...
708	*/
709	installMapListFile := func(m map[string]string, path string) android.OutputPath {
710		var txtBuilder strings.Builder
711		for idx, k := range android.SortedStringKeys(m) {
712			if idx > 0 {
713				txtBuilder.WriteString("\\n")
714			}
715			txtBuilder.WriteString(k)
716			txtBuilder.WriteString(" ")
717			txtBuilder.WriteString(m[k])
718		}
719		return writeStringToFile(ctx, txtBuilder.String(), path)
720	}
721
722	/*
723		module_paths.txt contains paths on which VNDK modules are defined.
724		e.g.,
725			libbase.so system/core/base
726			libc.so bionic/libc
727			...
728	*/
729	snapshotOutputs = append(snapshotOutputs, installMapListFile(modulePaths, filepath.Join(configsDir, "module_paths.txt")))
730
731	/*
732		module_names.txt contains names as which VNDK modules are defined,
733		because output filename and module name can be different with stem and suffix properties.
734
735		e.g.,
736			libcutils.so libcutils
737			libprotobuf-cpp-full-3.9.2.so libprotobuf-cpp-full
738			...
739	*/
740	snapshotOutputs = append(snapshotOutputs, installMapListFile(moduleNames, filepath.Join(configsDir, "module_names.txt")))
741
742	// All artifacts are ready. Sort them to normalize ninja and then zip.
743	sort.Slice(snapshotOutputs, func(i, j int) bool {
744		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
745	})
746
747	zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
748	zipRule := android.NewRuleBuilder()
749
750	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with xargs
751	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
752	zipRule.Command().
753		Text("tr").
754		FlagWithArg("-d ", "\\'").
755		FlagWithRspFileInputList("< ", snapshotOutputs).
756		FlagWithOutput("> ", snapshotOutputList)
757
758	zipRule.Temporary(snapshotOutputList)
759
760	zipRule.Command().
761		BuiltTool(ctx, "soong_zip").
762		FlagWithOutput("-o ", zipPath).
763		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
764		FlagWithInput("-l ", snapshotOutputList)
765
766	zipRule.Build(pctx, ctx, zipPath.String(), "vndk snapshot "+zipPath.String())
767	zipRule.DeleteTemporaryFiles()
768	c.vndkSnapshotZipFile = android.OptionalPathForPath(zipPath)
769}
770
771func getVndkFileName(m *Module) (string, error) {
772	if library, ok := m.linker.(*libraryDecorator); ok {
773		return library.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil
774	}
775	if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok {
776		return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil
777	}
778	return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker)
779}
780
781func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.SingletonContext) {
782	llndk := android.SortedStringMapValues(llndkLibraries(ctx.Config()))
783	vndkcore := android.SortedStringMapValues(vndkCoreLibraries(ctx.Config()))
784	vndksp := android.SortedStringMapValues(vndkSpLibraries(ctx.Config()))
785	vndkprivate := android.SortedStringMapValues(vndkPrivateLibraries(ctx.Config()))
786
787	// Build list of vndk libs as merged & tagged & filter-out(libclang_rt):
788	// Since each target have different set of libclang_rt.* files,
789	// keep the common set of files in vndk.libraries.txt
790	var merged []string
791	filterOutLibClangRt := func(libList []string) (filtered []string) {
792		for _, lib := range libList {
793			if !strings.HasPrefix(lib, "libclang_rt.") {
794				filtered = append(filtered, lib)
795			}
796		}
797		return
798	}
799	merged = append(merged, addPrefix(filterOutLibClangRt(llndk), "LLNDK: ")...)
800	merged = append(merged, addPrefix(vndksp, "VNDK-SP: ")...)
801	merged = append(merged, addPrefix(filterOutLibClangRt(vndkcore), "VNDK-core: ")...)
802	merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...)
803	c.vndkLibrariesFile = android.PathForOutput(ctx, "vndk", "vndk.libraries.txt")
804	ctx.Build(pctx, android.BuildParams{
805		Rule:        android.WriteFile,
806		Output:      c.vndkLibrariesFile,
807		Description: "Writing " + c.vndkLibrariesFile.String(),
808		Args: map[string]string{
809			"content": strings.Join(merged, "\\n"),
810		},
811	})
812}
813
814func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
815	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
816	// they been moved to an apex.
817	movedToApexLlndkLibraries := []string{}
818	for lib := range llndkLibraries(ctx.Config()) {
819		// Skip bionic libs, they are handled in different manner
820		if android.DirectlyInAnyApex(&notOnHostContext{}, lib) && !isBionic(lib) {
821			movedToApexLlndkLibraries = append(movedToApexLlndkLibraries, lib)
822		}
823	}
824	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(movedToApexLlndkLibraries, " "))
825
826	// Make uses LLNDK_LIBRARIES to determine which libraries to install.
827	// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
828	// Therefore, by removing the library here, we cause it to only be installed if libc
829	// depends on it.
830	installedLlndkLibraries := []string{}
831	for lib := range llndkLibraries(ctx.Config()) {
832		if strings.HasPrefix(lib, "libclang_rt.hwasan-") {
833			continue
834		}
835		installedLlndkLibraries = append(installedLlndkLibraries, lib)
836	}
837	sort.Strings(installedLlndkLibraries)
838	ctx.Strict("LLNDK_LIBRARIES", strings.Join(installedLlndkLibraries, " "))
839
840	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(android.SortedStringKeys(vndkCoreLibraries(ctx.Config())), " "))
841	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(android.SortedStringKeys(vndkSpLibraries(ctx.Config())), " "))
842	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(android.SortedStringKeys(vndkPrivateLibraries(ctx.Config())), " "))
843	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(android.SortedStringKeys(vndkUsingCoreVariantLibraries(ctx.Config())), " "))
844
845	ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String())
846	ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String())
847}
848