• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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() {
314		mctx.PropertyErrorf("vndk.enabled", "This library provides stubs. Shouldn't be VNDK. Consider making it as LLNDK")
315	}
316
317	vndkLibrariesLock.Lock()
318	defer vndkLibrariesLock.Unlock()
319
320	if inList(name, vndkMustUseVendorVariantList(mctx.Config())) {
321		m.Properties.MustUseVendorVariant = true
322	}
323	if mctx.DeviceConfig().VndkUseCoreVariant() && !m.Properties.MustUseVendorVariant {
324		vndkUsingCoreVariantLibraries(mctx.Config())[name] = filename
325	}
326
327	if m.vndkdep.isVndkSp() {
328		vndkSpLibraries(mctx.Config())[name] = filename
329	} else {
330		vndkCoreLibraries(mctx.Config())[name] = filename
331	}
332	if !Bool(m.VendorProperties.Vendor_available) {
333		vndkPrivateLibraries(mctx.Config())[name] = filename
334	}
335}
336
337// Sanity check for modules that mustn't be VNDK
338func shouldSkipVndkMutator(m *Module) bool {
339	if !m.Enabled() {
340		return true
341	}
342	if !m.Device() {
343		// Skip non-device modules
344		return true
345	}
346	if m.Target().NativeBridge == android.NativeBridgeEnabled {
347		// Skip native_bridge modules
348		return true
349	}
350	return false
351}
352
353func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool {
354	if shouldSkipVndkMutator(m) {
355		return false
356	}
357
358	// prebuilt vndk modules should match with device
359	// TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared
360	// When b/142675459 is landed, remove following check
361	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.matchesWithDevice(mctx.DeviceConfig()) {
362		return false
363	}
364
365	if lib, ok := m.linker.(libraryInterface); ok {
366		// VNDK APEX for VNDK-Lite devices will have VNDK-SP libraries from core variants
367		if mctx.DeviceConfig().VndkVersion() == "" {
368			// b/73296261: filter out libz.so because it is considered as LLNDK for VNDK-lite devices
369			if mctx.ModuleName() == "libz" {
370				return false
371			}
372			return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.isVndkSp()
373		}
374
375		useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
376			mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
377		return lib.shared() && m.inVendor() && m.IsVndk() && !m.isVndkExt() && !useCoreVariant
378	}
379	return false
380}
381
382// gather list of vndk-core, vndk-sp, and ll-ndk libs
383func VndkMutator(mctx android.BottomUpMutatorContext) {
384	m, ok := mctx.Module().(*Module)
385	if !ok {
386		return
387	}
388
389	if shouldSkipVndkMutator(m) {
390		return
391	}
392
393	if _, ok := m.linker.(*llndkStubDecorator); ok {
394		processLlndkLibrary(mctx, m)
395		return
396	}
397
398	lib, is_lib := m.linker.(*libraryDecorator)
399	prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
400
401	if (is_lib && lib.buildShared()) || (is_prebuilt_lib && prebuilt_lib.buildShared()) {
402		if m.vndkdep != nil && m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
403			processVndkLibrary(mctx, m)
404			return
405		}
406	}
407}
408
409func init() {
410	android.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
411	android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
412}
413
414type vndkLibrariesTxt struct {
415	android.ModuleBase
416	outputFile android.OutputPath
417}
418
419var _ etc.PrebuiltEtcModule = &vndkLibrariesTxt{}
420var _ android.OutputFileProducer = &vndkLibrariesTxt{}
421
422// vndk_libraries_txt is a special kind of module type in that it name is one of
423// - llndk.libraries.txt
424// - vndkcore.libraries.txt
425// - vndksp.libraries.txt
426// - vndkprivate.libraries.txt
427// - vndkcorevariant.libraries.txt
428// A module behaves like a prebuilt_etc but its content is generated by soong.
429// By being a soong module, these files can be referenced by other soong modules.
430// For example, apex_vndk can depend on these files as prebuilt.
431func VndkLibrariesTxtFactory() android.Module {
432	m := &vndkLibrariesTxt{}
433	android.InitAndroidModule(m)
434	return m
435}
436
437func insertVndkVersion(filename string, vndkVersion string) string {
438	if index := strings.LastIndex(filename, "."); index != -1 {
439		return filename[:index] + "." + vndkVersion + filename[index:]
440	}
441	return filename
442}
443
444func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
445	var list []string
446	switch txt.Name() {
447	case llndkLibrariesTxt:
448		for _, filename := range android.SortedStringMapValues(llndkLibraries(ctx.Config())) {
449			if strings.HasPrefix(filename, "libclang_rt.hwasan-") {
450				continue
451			}
452			list = append(list, filename)
453		}
454	case vndkCoreLibrariesTxt:
455		list = android.SortedStringMapValues(vndkCoreLibraries(ctx.Config()))
456	case vndkSpLibrariesTxt:
457		list = android.SortedStringMapValues(vndkSpLibraries(ctx.Config()))
458	case vndkPrivateLibrariesTxt:
459		list = android.SortedStringMapValues(vndkPrivateLibraries(ctx.Config()))
460	case vndkUsingCoreVariantLibrariesTxt:
461		list = android.SortedStringMapValues(vndkUsingCoreVariantLibraries(ctx.Config()))
462	default:
463		ctx.ModuleErrorf("name(%s) is unknown.", txt.Name())
464		return
465	}
466
467	var filename string
468	if txt.Name() != vndkUsingCoreVariantLibrariesTxt {
469		filename = insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion())
470	} else {
471		filename = txt.Name()
472	}
473
474	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
475	ctx.Build(pctx, android.BuildParams{
476		Rule:        android.WriteFile,
477		Output:      txt.outputFile,
478		Description: "Writing " + txt.outputFile.String(),
479		Args: map[string]string{
480			"content": strings.Join(list, "\\n"),
481		},
482	})
483
484	installPath := android.PathForModuleInstall(ctx, "etc")
485	ctx.InstallFile(installPath, filename, txt.outputFile)
486}
487
488func (txt *vndkLibrariesTxt) AndroidMkEntries() []android.AndroidMkEntries {
489	return []android.AndroidMkEntries{android.AndroidMkEntries{
490		Class:      "ETC",
491		OutputFile: android.OptionalPathForPath(txt.outputFile),
492		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
493			func(entries *android.AndroidMkEntries) {
494				entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base())
495			},
496		},
497	}}
498}
499
500func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath {
501	return txt.outputFile
502}
503
504func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
505	return android.Paths{txt.outputFile}, nil
506}
507
508func (txt *vndkLibrariesTxt) SubDir() string {
509	return ""
510}
511
512func VndkSnapshotSingleton() android.Singleton {
513	return &vndkSnapshotSingleton{}
514}
515
516type vndkSnapshotSingleton struct {
517	vndkLibrariesFile   android.OutputPath
518	vndkSnapshotZipFile android.OptionalPath
519}
520
521func isVndkSnapshotLibrary(config android.DeviceConfig, m *Module) (i snapshotLibraryInterface, vndkType string, isVndkSnapshotLib bool) {
522	if m.Target().NativeBridge == android.NativeBridgeEnabled {
523		return nil, "", false
524	}
525	if !m.inVendor() || !m.installable() || m.isSnapshotPrebuilt() {
526		return nil, "", false
527	}
528	l, ok := m.linker.(snapshotLibraryInterface)
529	if !ok || !l.shared() {
530		return nil, "", false
531	}
532	if m.VndkVersion() == config.PlatformVndkVersion() && m.IsVndk() && !m.isVndkExt() {
533		if m.isVndkSp() {
534			return l, "vndk-sp", true
535		} else {
536			return l, "vndk-core", true
537		}
538	}
539
540	return nil, "", false
541}
542
543func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
544	// build these files even if PlatformVndkVersion or BoardVndkVersion is not set
545	c.buildVndkLibrariesTxtFiles(ctx)
546
547	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
548	if ctx.DeviceConfig().VndkVersion() != "current" {
549		return
550	}
551
552	if ctx.DeviceConfig().PlatformVndkVersion() == "" {
553		return
554	}
555
556	if ctx.DeviceConfig().BoardVndkRuntimeDisable() {
557		return
558	}
559
560	var snapshotOutputs android.Paths
561
562	/*
563		VNDK snapshot zipped artifacts directory structure:
564		{SNAPSHOT_ARCH}/
565			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
566				shared/
567					vndk-core/
568						(VNDK-core libraries, e.g. libbinder.so)
569					vndk-sp/
570						(VNDK-SP libraries, e.g. libc++.so)
571			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
572				shared/
573					vndk-core/
574						(VNDK-core libraries, e.g. libbinder.so)
575					vndk-sp/
576						(VNDK-SP libraries, e.g. libc++.so)
577			binder32/
578				(This directory is newly introduced in v28 (Android P) to hold
579				prebuilts built for 32-bit binder interface.)
580				arch-{TARGET_ARCH}-{TARGE_ARCH_VARIANT}/
581					...
582			configs/
583				(various *.txt configuration files)
584			include/
585				(header files of same directory structure with source tree)
586			NOTICE_FILES/
587				(notice files of libraries, e.g. libcutils.so.txt)
588	*/
589
590	snapshotDir := "vndk-snapshot"
591	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
592
593	configsDir := filepath.Join(snapshotArchDir, "configs")
594	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
595	includeDir := filepath.Join(snapshotArchDir, "include")
596
597	// set of notice files copied.
598	noticeBuilt := make(map[string]bool)
599
600	// paths of VNDK modules for GPL license checking
601	modulePaths := make(map[string]string)
602
603	// actual module names of .so files
604	// e.g. moduleNames["libprotobuf-cpp-full-3.9.1.so"] = "libprotobuf-cpp-full"
605	moduleNames := make(map[string]string)
606
607	var headers android.Paths
608
609	installVndkSnapshotLib := func(m *Module, l snapshotLibraryInterface, vndkType string) (android.Paths, bool) {
610		var ret android.Paths
611
612		targetArch := "arch-" + m.Target().Arch.ArchType.String()
613		if m.Target().Arch.ArchVariant != "" {
614			targetArch += "-" + m.Target().Arch.ArchVariant
615		}
616
617		libPath := m.outputFile.Path()
618		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
619		ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
620
621		if ctx.Config().VndkSnapshotBuildArtifacts() {
622			prop := struct {
623				ExportedDirs        []string `json:",omitempty"`
624				ExportedSystemDirs  []string `json:",omitempty"`
625				ExportedFlags       []string `json:",omitempty"`
626				RelativeInstallPath string   `json:",omitempty"`
627			}{}
628			prop.ExportedFlags = l.exportedFlags()
629			prop.ExportedDirs = l.exportedDirs().Strings()
630			prop.ExportedSystemDirs = l.exportedSystemDirs().Strings()
631			prop.RelativeInstallPath = m.RelativeInstallPath()
632
633			propOut := snapshotLibOut + ".json"
634
635			j, err := json.Marshal(prop)
636			if err != nil {
637				ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
638				return nil, false
639			}
640			ret = append(ret, writeStringToFile(ctx, string(j), propOut))
641		}
642		return ret, true
643	}
644
645	ctx.VisitAllModules(func(module android.Module) {
646		m, ok := module.(*Module)
647		if !ok || !m.Enabled() {
648			return
649		}
650
651		l, vndkType, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m)
652		if !ok {
653			return
654		}
655
656		// install .so files for appropriate modules.
657		// Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
658		libs, ok := installVndkSnapshotLib(m, l, vndkType)
659		if !ok {
660			return
661		}
662		snapshotOutputs = append(snapshotOutputs, libs...)
663
664		// These are for generating module_names.txt and module_paths.txt
665		stem := m.outputFile.Path().Base()
666		moduleNames[stem] = ctx.ModuleName(m)
667		modulePaths[stem] = ctx.ModuleDir(m)
668
669		if m.NoticeFile().Valid() {
670			noticeName := stem + ".txt"
671			// skip already copied notice file
672			if _, ok := noticeBuilt[noticeName]; !ok {
673				noticeBuilt[noticeName] = true
674				snapshotOutputs = append(snapshotOutputs, copyFile(
675					ctx, m.NoticeFile().Path(), filepath.Join(noticeDir, noticeName)))
676			}
677		}
678
679		if ctx.Config().VndkSnapshotBuildArtifacts() {
680			headers = append(headers, l.snapshotHeaders()...)
681		}
682	})
683
684	// install all headers after removing duplicates
685	for _, header := range android.FirstUniquePaths(headers) {
686		snapshotOutputs = append(snapshotOutputs, copyFile(
687			ctx, header, filepath.Join(includeDir, header.String())))
688	}
689
690	// install *.libraries.txt except vndkcorevariant.libraries.txt
691	ctx.VisitAllModules(func(module android.Module) {
692		m, ok := module.(*vndkLibrariesTxt)
693		if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
694			return
695		}
696		snapshotOutputs = append(snapshotOutputs, copyFile(
697			ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
698	})
699
700	/*
701		Dump a map to a list file as:
702
703		{key1} {value1}
704		{key2} {value2}
705		...
706	*/
707	installMapListFile := func(m map[string]string, path string) android.OutputPath {
708		var txtBuilder strings.Builder
709		for idx, k := range android.SortedStringKeys(m) {
710			if idx > 0 {
711				txtBuilder.WriteString("\\n")
712			}
713			txtBuilder.WriteString(k)
714			txtBuilder.WriteString(" ")
715			txtBuilder.WriteString(m[k])
716		}
717		return writeStringToFile(ctx, txtBuilder.String(), path)
718	}
719
720	/*
721		module_paths.txt contains paths on which VNDK modules are defined.
722		e.g.,
723			libbase.so system/core/base
724			libc.so bionic/libc
725			...
726	*/
727	snapshotOutputs = append(snapshotOutputs, installMapListFile(modulePaths, filepath.Join(configsDir, "module_paths.txt")))
728
729	/*
730		module_names.txt contains names as which VNDK modules are defined,
731		because output filename and module name can be different with stem and suffix properties.
732
733		e.g.,
734			libcutils.so libcutils
735			libprotobuf-cpp-full-3.9.2.so libprotobuf-cpp-full
736			...
737	*/
738	snapshotOutputs = append(snapshotOutputs, installMapListFile(moduleNames, filepath.Join(configsDir, "module_names.txt")))
739
740	// All artifacts are ready. Sort them to normalize ninja and then zip.
741	sort.Slice(snapshotOutputs, func(i, j int) bool {
742		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
743	})
744
745	zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
746	zipRule := android.NewRuleBuilder()
747
748	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with xargs
749	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
750	zipRule.Command().
751		Text("tr").
752		FlagWithArg("-d ", "\\'").
753		FlagWithRspFileInputList("< ", snapshotOutputs).
754		FlagWithOutput("> ", snapshotOutputList)
755
756	zipRule.Temporary(snapshotOutputList)
757
758	zipRule.Command().
759		BuiltTool(ctx, "soong_zip").
760		FlagWithOutput("-o ", zipPath).
761		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
762		FlagWithInput("-l ", snapshotOutputList)
763
764	zipRule.Build(pctx, ctx, zipPath.String(), "vndk snapshot "+zipPath.String())
765	zipRule.DeleteTemporaryFiles()
766	c.vndkSnapshotZipFile = android.OptionalPathForPath(zipPath)
767}
768
769func getVndkFileName(m *Module) (string, error) {
770	if library, ok := m.linker.(*libraryDecorator); ok {
771		return library.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil
772	}
773	if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok {
774		return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true) + ".so", nil
775	}
776	return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker)
777}
778
779func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.SingletonContext) {
780	llndk := android.SortedStringMapValues(llndkLibraries(ctx.Config()))
781	vndkcore := android.SortedStringMapValues(vndkCoreLibraries(ctx.Config()))
782	vndksp := android.SortedStringMapValues(vndkSpLibraries(ctx.Config()))
783	vndkprivate := android.SortedStringMapValues(vndkPrivateLibraries(ctx.Config()))
784
785	// Build list of vndk libs as merged & tagged & filter-out(libclang_rt):
786	// Since each target have different set of libclang_rt.* files,
787	// keep the common set of files in vndk.libraries.txt
788	var merged []string
789	filterOutLibClangRt := func(libList []string) (filtered []string) {
790		for _, lib := range libList {
791			if !strings.HasPrefix(lib, "libclang_rt.") {
792				filtered = append(filtered, lib)
793			}
794		}
795		return
796	}
797	merged = append(merged, addPrefix(filterOutLibClangRt(llndk), "LLNDK: ")...)
798	merged = append(merged, addPrefix(vndksp, "VNDK-SP: ")...)
799	merged = append(merged, addPrefix(filterOutLibClangRt(vndkcore), "VNDK-core: ")...)
800	merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...)
801	c.vndkLibrariesFile = android.PathForOutput(ctx, "vndk", "vndk.libraries.txt")
802	ctx.Build(pctx, android.BuildParams{
803		Rule:        android.WriteFile,
804		Output:      c.vndkLibrariesFile,
805		Description: "Writing " + c.vndkLibrariesFile.String(),
806		Args: map[string]string{
807			"content": strings.Join(merged, "\\n"),
808		},
809	})
810}
811
812func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
813	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
814	// they been moved to an apex.
815	movedToApexLlndkLibraries := []string{}
816	for lib := range llndkLibraries(ctx.Config()) {
817		// Skip bionic libs, they are handled in different manner
818		if android.DirectlyInAnyApex(&notOnHostContext{}, lib) && !isBionic(lib) {
819			movedToApexLlndkLibraries = append(movedToApexLlndkLibraries, lib)
820		}
821	}
822	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(movedToApexLlndkLibraries, " "))
823
824	// Make uses LLNDK_LIBRARIES to determine which libraries to install.
825	// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
826	// Therefore, by removing the library here, we cause it to only be installed if libc
827	// depends on it.
828	installedLlndkLibraries := []string{}
829	for lib := range llndkLibraries(ctx.Config()) {
830		if strings.HasPrefix(lib, "libclang_rt.hwasan-") {
831			continue
832		}
833		installedLlndkLibraries = append(installedLlndkLibraries, lib)
834	}
835	sort.Strings(installedLlndkLibraries)
836	ctx.Strict("LLNDK_LIBRARIES", strings.Join(installedLlndkLibraries, " "))
837
838	ctx.Strict("VNDK_CORE_LIBRARIES", strings.Join(android.SortedStringKeys(vndkCoreLibraries(ctx.Config())), " "))
839	ctx.Strict("VNDK_SAMEPROCESS_LIBRARIES", strings.Join(android.SortedStringKeys(vndkSpLibraries(ctx.Config())), " "))
840	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(android.SortedStringKeys(vndkPrivateLibraries(ctx.Config())), " "))
841	ctx.Strict("VNDK_USING_CORE_VARIANT_LIBRARIES", strings.Join(android.SortedStringKeys(vndkUsingCoreVariantLibraries(ctx.Config())), " "))
842
843	ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String())
844	ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String())
845}
846