• 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
25	"android/soong/android"
26	"android/soong/cc/config"
27	"android/soong/etc"
28	"android/soong/snapshot"
29
30	"github.com/google/blueprint"
31)
32
33const (
34	llndkLibrariesTxt                = "llndk.libraries.txt"
35	vndkCoreLibrariesTxt             = "vndkcore.libraries.txt"
36	vndkSpLibrariesTxt               = "vndksp.libraries.txt"
37	vndkPrivateLibrariesTxt          = "vndkprivate.libraries.txt"
38	vndkProductLibrariesTxt          = "vndkproduct.libraries.txt"
39	vndkUsingCoreVariantLibrariesTxt = "vndkcorevariant.libraries.txt"
40)
41
42func VndkLibrariesTxtModules(vndkVersion string) []string {
43	if vndkVersion == "current" {
44		return []string{
45			llndkLibrariesTxt,
46			vndkCoreLibrariesTxt,
47			vndkSpLibrariesTxt,
48			vndkPrivateLibrariesTxt,
49			vndkProductLibrariesTxt,
50		}
51	}
52	// Snapshot vndks have their own *.libraries.VER.txt files.
53	// Note that snapshots don't have "vndkcorevariant.libraries.VER.txt"
54	return []string{
55		insertVndkVersion(llndkLibrariesTxt, vndkVersion),
56		insertVndkVersion(vndkCoreLibrariesTxt, vndkVersion),
57		insertVndkVersion(vndkSpLibrariesTxt, vndkVersion),
58		insertVndkVersion(vndkPrivateLibrariesTxt, vndkVersion),
59		insertVndkVersion(vndkProductLibrariesTxt, vndkVersion),
60	}
61}
62
63type VndkProperties struct {
64	Vndk struct {
65		// declared as a VNDK or VNDK-SP module. The vendor variant
66		// will be installed in /system instead of /vendor partition.
67		//
68		// `vendor_available` and `product_available` must be explicitly
69		// set to either true or false together with `vndk: {enabled: true}`.
70		Enabled *bool
71
72		// declared as a VNDK-SP module, which is a subset of VNDK.
73		//
74		// `vndk: { enabled: true }` must set together.
75		//
76		// All these modules are allowed to link to VNDK-SP or LL-NDK
77		// modules only. Other dependency will cause link-type errors.
78		//
79		// If `support_system_process` is not set or set to false,
80		// the module is VNDK-core and can link to other VNDK-core,
81		// VNDK-SP or LL-NDK modules only.
82		Support_system_process *bool
83
84		// declared as a VNDK-private module.
85		// This module still creates the vendor and product variants refering
86		// to the `vendor_available: true` and `product_available: true`
87		// properties. However, it is only available to the other VNDK modules
88		// but not to the non-VNDK vendor or product modules.
89		Private *bool
90
91		// Extending another module
92		Extends *string
93	}
94}
95
96type vndkdep struct {
97	Properties VndkProperties
98}
99
100func (vndk *vndkdep) props() []interface{} {
101	return []interface{}{&vndk.Properties}
102}
103
104func (vndk *vndkdep) isVndk() bool {
105	return Bool(vndk.Properties.Vndk.Enabled)
106}
107
108func (vndk *vndkdep) isVndkSp() bool {
109	return Bool(vndk.Properties.Vndk.Support_system_process)
110}
111
112func (vndk *vndkdep) isVndkExt() bool {
113	return vndk.Properties.Vndk.Extends != nil
114}
115
116func (vndk *vndkdep) getVndkExtendsModuleName() string {
117	return String(vndk.Properties.Vndk.Extends)
118}
119
120func (vndk *vndkdep) typeName() string {
121	if !vndk.isVndk() {
122		return "native:vendor"
123	}
124	if !vndk.isVndkExt() {
125		if !vndk.isVndkSp() {
126			return "native:vendor:vndk"
127		}
128		return "native:vendor:vndksp"
129	}
130	if !vndk.isVndkSp() {
131		return "native:vendor:vndkext"
132	}
133	return "native:vendor:vndkspext"
134}
135
136// VNDK link type check from a module with UseVndk() == true.
137func (vndk *vndkdep) vndkCheckLinkType(ctx android.BaseModuleContext, to *Module, tag blueprint.DependencyTag) {
138	if to.linker == nil {
139		return
140	}
141	if !vndk.isVndk() {
142		// Non-VNDK modules those installed to /vendor, /system/vendor,
143		// /product or /system/product cannot depend on VNDK-private modules
144		// that include VNDK-core-private, VNDK-SP-private and LLNDK-private.
145		if to.IsVndkPrivate() {
146			ctx.ModuleErrorf("non-VNDK module should not link to %q which has `private: true`", to.Name())
147		}
148	}
149	if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() {
150		// Check only shared libraries.
151		// Other (static) libraries are allowed to link.
152		return
153	}
154
155	if to.IsLlndk() {
156		// LL-NDK libraries are allowed to link
157		return
158	}
159
160	if !to.UseVndk() {
161		ctx.ModuleErrorf("(%s) should not link to %q which is not a vendor-available library",
162			vndk.typeName(), to.Name())
163		return
164	}
165	if tag == vndkExtDepTag {
166		// Ensure `extends: "name"` property refers a vndk module that has vendor_available
167		// and has identical vndk properties.
168		if to.vndkdep == nil || !to.vndkdep.isVndk() {
169			ctx.ModuleErrorf("`extends` refers a non-vndk module %q", to.Name())
170			return
171		}
172		if vndk.isVndkSp() != to.vndkdep.isVndkSp() {
173			ctx.ModuleErrorf(
174				"`extends` refers a module %q with mismatched support_system_process",
175				to.Name())
176			return
177		}
178		if to.IsVndkPrivate() {
179			ctx.ModuleErrorf(
180				"`extends` refers module %q which has `private: true`",
181				to.Name())
182			return
183		}
184	}
185	if to.vndkdep == nil {
186		return
187	}
188
189	// Check the dependencies of VNDK shared libraries.
190	if err := vndkIsVndkDepAllowed(vndk, to.vndkdep); err != nil {
191		ctx.ModuleErrorf("(%s) should not link to %q (%s): %v",
192			vndk.typeName(), to.Name(), to.vndkdep.typeName(), err)
193		return
194	}
195}
196
197func vndkIsVndkDepAllowed(from *vndkdep, to *vndkdep) error {
198	// Check the dependencies of VNDK, VNDK-Ext, VNDK-SP, VNDK-SP-Ext and vendor modules.
199	if from.isVndkExt() {
200		if from.isVndkSp() {
201			if to.isVndk() && !to.isVndkSp() {
202				return errors.New("VNDK-SP extensions must not depend on VNDK or VNDK extensions")
203			}
204			return nil
205		}
206		// VNDK-Ext may depend on VNDK, VNDK-Ext, VNDK-SP, VNDK-SP-Ext, or vendor libs.
207		return nil
208	}
209	if from.isVndk() {
210		if to.isVndkExt() {
211			return errors.New("VNDK-core and VNDK-SP must not depend on VNDK extensions")
212		}
213		if from.isVndkSp() {
214			if !to.isVndkSp() {
215				return errors.New("VNDK-SP must only depend on VNDK-SP")
216			}
217			return nil
218		}
219		if !to.isVndk() {
220			return errors.New("VNDK-core must only depend on VNDK-core or VNDK-SP")
221		}
222		return nil
223	}
224	// Vendor modules may depend on VNDK, VNDK-Ext, VNDK-SP, VNDK-SP-Ext, or vendor libs.
225	return nil
226}
227
228type moduleListerFunc func(ctx android.SingletonContext) (moduleNames, fileNames []string)
229
230var (
231	llndkLibraries                = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsLLNDK && !m.Header() })
232	vndkSPLibraries               = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKSP })
233	vndkCoreLibraries             = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKCore })
234	vndkPrivateLibraries          = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKPrivate })
235	vndkProductLibraries          = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKProduct })
236	vndkUsingCoreVariantLibraries = vndkModuleLister(func(m *Module) bool { return m.VendorProperties.IsVNDKUsingCoreVariant })
237)
238
239// vndkModuleLister takes a predicate that operates on a Module and returns a moduleListerFunc
240// that produces a list of module names and output file names for which the predicate returns true.
241func vndkModuleLister(predicate func(*Module) bool) moduleListerFunc {
242	return func(ctx android.SingletonContext) (moduleNames, fileNames []string) {
243		ctx.VisitAllModules(func(m android.Module) {
244			if c, ok := m.(*Module); ok && predicate(c) && !c.IsVndkPrebuiltLibrary() {
245				filename, err := getVndkFileName(c)
246				if err != nil {
247					ctx.ModuleErrorf(m, "%s", err)
248				}
249				moduleNames = append(moduleNames, ctx.ModuleName(m))
250				fileNames = append(fileNames, filename)
251			}
252		})
253		moduleNames = android.SortedUniqueStrings(moduleNames)
254		fileNames = android.SortedUniqueStrings(fileNames)
255		return
256	}
257}
258
259// vndkModuleListRemover takes a moduleListerFunc and a prefix and returns a moduleListerFunc
260// that returns the same lists as the input moduleListerFunc, but with  modules with the
261// given prefix removed.
262func vndkModuleListRemover(lister moduleListerFunc, prefix string) moduleListerFunc {
263	return func(ctx android.SingletonContext) (moduleNames, fileNames []string) {
264		moduleNames, fileNames = lister(ctx)
265		filter := func(in []string) []string {
266			out := make([]string, 0, len(in))
267			for _, lib := range in {
268				if strings.HasPrefix(lib, prefix) {
269					continue
270				}
271				out = append(out, lib)
272			}
273			return out
274		}
275		return filter(moduleNames), filter(fileNames)
276	}
277}
278
279var vndkMustUseVendorVariantListKey = android.NewOnceKey("vndkMustUseVendorVariantListKey")
280
281func vndkMustUseVendorVariantList(cfg android.Config) []string {
282	return cfg.Once(vndkMustUseVendorVariantListKey, func() interface{} {
283		return config.VndkMustUseVendorVariantList
284	}).([]string)
285}
286
287// test may call this to override global configuration(config.VndkMustUseVendorVariantList)
288// when it is called, it must be before the first call to vndkMustUseVendorVariantList()
289func setVndkMustUseVendorVariantListForTest(config android.Config, mustUseVendorVariantList []string) {
290	config.Once(vndkMustUseVendorVariantListKey, func() interface{} {
291		return mustUseVendorVariantList
292	})
293}
294
295func processVndkLibrary(mctx android.BottomUpMutatorContext, m *Module) {
296	if m.InProduct() {
297		// We may skip the steps for the product variants because they
298		// are already covered by the vendor variants.
299		return
300	}
301
302	name := m.BaseModuleName()
303
304	if lib := m.library; lib != nil && lib.hasStubsVariants() && name != "libz" {
305		// b/155456180 libz is the ONLY exception here. We don't want to make
306		// libz an LLNDK library because we in general can't guarantee that
307		// libz will behave consistently especially about the compression.
308		// i.e. the compressed output might be different across releases.
309		// As the library is an external one, it's risky to keep the compatibility
310		// promise if it becomes an LLNDK.
311		mctx.PropertyErrorf("vndk.enabled", "This library provides stubs. Shouldn't be VNDK. Consider making it as LLNDK")
312	}
313
314	if inList(name, vndkMustUseVendorVariantList(mctx.Config())) {
315		m.Properties.MustUseVendorVariant = true
316	}
317	if mctx.DeviceConfig().VndkUseCoreVariant() && !m.Properties.MustUseVendorVariant {
318		m.VendorProperties.IsVNDKUsingCoreVariant = true
319	}
320
321	if m.vndkdep.isVndkSp() {
322		m.VendorProperties.IsVNDKSP = true
323	} else {
324		m.VendorProperties.IsVNDKCore = true
325	}
326	if m.IsVndkPrivate() {
327		m.VendorProperties.IsVNDKPrivate = true
328	}
329	if Bool(m.VendorProperties.Product_available) {
330		m.VendorProperties.IsVNDKProduct = true
331	}
332}
333
334// Check for modules that mustn't be VNDK
335func shouldSkipVndkMutator(m *Module) bool {
336	if !m.Enabled() {
337		return true
338	}
339	if !m.Device() {
340		// Skip non-device modules
341		return true
342	}
343	if m.Target().NativeBridge == android.NativeBridgeEnabled {
344		// Skip native_bridge modules
345		return true
346	}
347	return false
348}
349
350func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool {
351	if shouldSkipVndkMutator(m) {
352		return false
353	}
354
355	// prebuilt vndk modules should match with device
356	// TODO(b/142675459): Use enabled: to select target device in vndk_prebuilt_shared
357	// When b/142675459 is landed, remove following check
358	if p, ok := m.linker.(*vndkPrebuiltLibraryDecorator); ok && !p.MatchesWithDevice(mctx.DeviceConfig()) {
359		return false
360	}
361
362	if lib, ok := m.linker.(libraryInterface); ok {
363		// VNDK APEX for VNDK-Lite devices will have VNDK-SP libraries from core variants
364		if mctx.DeviceConfig().VndkVersion() == "" {
365			// b/73296261: filter out libz.so because it is considered as LLNDK for VNDK-lite devices
366			if mctx.ModuleName() == "libz" {
367				return false
368			}
369			return m.ImageVariation().Variation == android.CoreVariation && lib.shared() && m.IsVndkSp() && !m.IsVndkExt()
370		}
371		// VNDK APEX doesn't need stub variants
372		if lib.buildStubs() {
373			return false
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	lib, isLib := m.linker.(*libraryDecorator)
394	prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker)
395
396	if m.UseVndk() && isLib && lib.hasLLNDKStubs() {
397		m.VendorProperties.IsLLNDK = true
398		m.VendorProperties.IsVNDKPrivate = Bool(lib.Properties.Llndk.Private)
399	}
400	if m.UseVndk() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() {
401		m.VendorProperties.IsLLNDK = true
402		m.VendorProperties.IsVNDKPrivate = Bool(prebuiltLib.Properties.Llndk.Private)
403	}
404
405	if m.IsVndkPrebuiltLibrary() && !m.IsVndk() {
406		m.VendorProperties.IsLLNDK = true
407		// TODO(b/280697209): copy "llndk.private" flag to vndk_prebuilt_shared
408	}
409
410	if (isLib && lib.buildShared()) || (isPrebuiltLib && prebuiltLib.buildShared()) {
411		if m.vndkdep != nil && m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
412			processVndkLibrary(mctx, m)
413			return
414		}
415	}
416}
417
418func init() {
419	RegisterVndkLibraryTxtTypes(android.InitRegistrationContext)
420	android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
421}
422
423func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) {
424	ctx.RegisterSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
425	ctx.RegisterSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory)
426	ctx.RegisterSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory)
427	ctx.RegisterSingletonModuleType("vndkprivate_libraries_txt", vndkPrivateLibrariesTxtFactory)
428	ctx.RegisterSingletonModuleType("vndkproduct_libraries_txt", vndkProductLibrariesTxtFactory)
429	ctx.RegisterSingletonModuleType("vndkcorevariant_libraries_txt", vndkUsingCoreVariantLibrariesTxtFactory)
430}
431
432type vndkLibrariesTxt struct {
433	android.SingletonModuleBase
434
435	lister               moduleListerFunc
436	makeVarName          string
437	filterOutFromMakeVar string
438
439	properties VndkLibrariesTxtProperties
440
441	outputFile  android.OutputPath
442	moduleNames []string
443	fileNames   []string
444}
445
446type VndkLibrariesTxtProperties struct {
447	Insert_vndk_version *bool
448}
449
450var _ etc.PrebuiltEtcModule = &vndkLibrariesTxt{}
451var _ android.OutputFileProducer = &vndkLibrariesTxt{}
452
453// llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries
454// generated by Soong but can be referenced by other modules.
455// For example, apex_vndk can depend on these files as prebuilt.
456// Make uses LLNDK_LIBRARIES to determine which libraries to install.
457// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
458// Therefore, by removing the library here, we cause it to only be installed if libc
459// depends on it.
460func llndkLibrariesTxtFactory() android.SingletonModule {
461	return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan")
462}
463
464// vndksp_libraries_txt is a singleton module whose content is a list of VNDKSP libraries
465// generated by Soong but can be referenced by other modules.
466// For example, apex_vndk can depend on these files as prebuilt.
467func vndkSPLibrariesTxtFactory() android.SingletonModule {
468	return newVndkLibrariesTxt(vndkSPLibraries, "VNDK_SAMEPROCESS_LIBRARIES")
469}
470
471// vndkcore_libraries_txt is a singleton module whose content is a list of VNDK core libraries
472// generated by Soong but can be referenced by other modules.
473// For example, apex_vndk can depend on these files as prebuilt.
474func vndkCoreLibrariesTxtFactory() android.SingletonModule {
475	return newVndkLibrariesTxt(vndkCoreLibraries, "VNDK_CORE_LIBRARIES")
476}
477
478// vndkprivate_libraries_txt is a singleton module whose content is a list of VNDK private libraries
479// generated by Soong but can be referenced by other modules.
480// For example, apex_vndk can depend on these files as prebuilt.
481func vndkPrivateLibrariesTxtFactory() android.SingletonModule {
482	return newVndkLibrariesTxt(vndkPrivateLibraries, "VNDK_PRIVATE_LIBRARIES")
483}
484
485// vndkproduct_libraries_txt is a singleton module whose content is a list of VNDK product libraries
486// generated by Soong but can be referenced by other modules.
487// For example, apex_vndk can depend on these files as prebuilt.
488func vndkProductLibrariesTxtFactory() android.SingletonModule {
489	return newVndkLibrariesTxt(vndkProductLibraries, "VNDK_PRODUCT_LIBRARIES")
490}
491
492// vndkcorevariant_libraries_txt is a singleton module whose content is a list of VNDK libraries
493// that are using the core variant, generated by Soong but can be referenced by other modules.
494// For example, apex_vndk can depend on these files as prebuilt.
495func vndkUsingCoreVariantLibrariesTxtFactory() android.SingletonModule {
496	return newVndkLibrariesTxt(vndkUsingCoreVariantLibraries, "VNDK_USING_CORE_VARIANT_LIBRARIES")
497}
498
499func newVndkLibrariesWithMakeVarFilter(lister moduleListerFunc, makeVarName string, filter string) android.SingletonModule {
500	m := &vndkLibrariesTxt{
501		lister:               lister,
502		makeVarName:          makeVarName,
503		filterOutFromMakeVar: filter,
504	}
505	m.AddProperties(&m.properties)
506	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
507	return m
508}
509
510func newVndkLibrariesTxt(lister moduleListerFunc, makeVarName string) android.SingletonModule {
511	return newVndkLibrariesWithMakeVarFilter(lister, makeVarName, "")
512}
513
514func insertVndkVersion(filename string, vndkVersion string) string {
515	if index := strings.LastIndex(filename, "."); index != -1 {
516		return filename[:index] + "." + vndkVersion + filename[index:]
517	}
518	return filename
519}
520
521func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
522	var filename string
523	if BoolDefault(txt.properties.Insert_vndk_version, true) {
524		filename = insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion())
525	} else {
526		filename = txt.Name()
527	}
528
529	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
530
531	installPath := android.PathForModuleInstall(ctx, "etc")
532	ctx.InstallFile(installPath, filename, txt.outputFile)
533}
534
535func (txt *vndkLibrariesTxt) GenerateSingletonBuildActions(ctx android.SingletonContext) {
536	txt.moduleNames, txt.fileNames = txt.lister(ctx)
537	android.WriteFileRule(ctx, txt.outputFile, strings.Join(txt.fileNames, "\n"))
538}
539
540func (txt *vndkLibrariesTxt) AndroidMkEntries() []android.AndroidMkEntries {
541	return []android.AndroidMkEntries{android.AndroidMkEntries{
542		Class:      "ETC",
543		OutputFile: android.OptionalPathForPath(txt.outputFile),
544		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
545			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
546				entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base())
547			},
548		},
549	}}
550}
551
552func (txt *vndkLibrariesTxt) MakeVars(ctx android.MakeVarsContext) {
553	filter := func(modules []string, prefix string) []string {
554		if prefix == "" {
555			return modules
556		}
557		var result []string
558		for _, module := range modules {
559			if strings.HasPrefix(module, prefix) {
560				continue
561			} else {
562				result = append(result, module)
563			}
564		}
565		return result
566	}
567	ctx.Strict(txt.makeVarName, strings.Join(filter(txt.moduleNames, txt.filterOutFromMakeVar), " "))
568}
569
570// PrebuiltEtcModule interface
571func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath {
572	return txt.outputFile
573}
574
575// PrebuiltEtcModule interface
576func (txt *vndkLibrariesTxt) BaseDir() string {
577	return "etc"
578}
579
580// PrebuiltEtcModule interface
581func (txt *vndkLibrariesTxt) SubDir() string {
582	return ""
583}
584
585func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
586	return android.Paths{txt.outputFile}, nil
587}
588
589func VndkSnapshotSingleton() android.Singleton {
590	return &vndkSnapshotSingleton{}
591}
592
593type vndkSnapshotSingleton struct {
594	vndkLibrariesFile   android.OutputPath
595	vndkSnapshotZipFile android.OptionalPath
596}
597
598func isVndkSnapshotAware(config android.DeviceConfig, m LinkableInterface,
599	apexInfo android.ApexInfo) (vndkType string, isVndkSnapshotLib bool) {
600
601	if m.Target().NativeBridge == android.NativeBridgeEnabled {
602		return "", false
603	}
604	// !inVendor: There's product/vendor variants for VNDK libs. We only care about vendor variants.
605	// !installable: Snapshot only cares about "installable" modules.
606	// !m.IsLlndk: llndk stubs are required for building against snapshots.
607	// IsSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense.
608	// !outputFile.Valid: Snapshot requires valid output file.
609	if !m.InVendor() || (!installable(m, apexInfo) && !m.IsLlndk()) || m.IsSnapshotPrebuilt() || !m.OutputFile().Valid() {
610		return "", false
611	}
612	if !m.IsSnapshotLibrary() || !m.Shared() {
613		return "", false
614	}
615	if m.VndkVersion() == config.PlatformVndkVersion() {
616		if m.IsVndk() && !m.IsVndkExt() {
617			if m.IsVndkSp() {
618				return "vndk-sp", true
619			} else {
620				return "vndk-core", true
621			}
622		} else if m.HasLlndkStubs() && m.StubsVersion() == "" {
623			// Use default version for the snapshot.
624			return "llndk-stub", true
625		}
626	}
627
628	return "", false
629}
630
631func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
632	// build these files even if PlatformVndkVersion or BoardVndkVersion is not set
633	c.buildVndkLibrariesTxtFiles(ctx)
634
635	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
636	if ctx.DeviceConfig().VndkVersion() != "current" {
637		return
638	}
639
640	if ctx.DeviceConfig().PlatformVndkVersion() == "" {
641		return
642	}
643
644	var snapshotOutputs android.Paths
645
646	/*
647		VNDK snapshot zipped artifacts directory structure:
648		{SNAPSHOT_ARCH}/
649			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
650				shared/
651					vndk-core/
652						(VNDK-core libraries, e.g. libbinder.so)
653					vndk-sp/
654						(VNDK-SP libraries, e.g. libc++.so)
655					llndk-stub/
656						(LLNDK stub libraries)
657			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
658				shared/
659					vndk-core/
660						(VNDK-core libraries, e.g. libbinder.so)
661					vndk-sp/
662						(VNDK-SP libraries, e.g. libc++.so)
663					llndk-stub/
664						(LLNDK stub libraries)
665			binder32/
666				(This directory is newly introduced in v28 (Android P) to hold
667				prebuilts built for 32-bit binder interface.)
668				arch-{TARGET_ARCH}-{TARGE_ARCH_VARIANT}/
669					...
670			configs/
671				(various *.txt configuration files)
672			include/
673				(header files of same directory structure with source tree)
674			NOTICE_FILES/
675				(notice files of libraries, e.g. libcutils.so.txt)
676	*/
677
678	snapshotDir := "vndk-snapshot"
679	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
680
681	configsDir := filepath.Join(snapshotArchDir, "configs")
682	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
683	includeDir := filepath.Join(snapshotArchDir, "include")
684
685	// set of notice files copied.
686	noticeBuilt := make(map[string]bool)
687
688	// paths of VNDK modules for GPL license checking
689	modulePaths := make(map[string]string)
690
691	// actual module names of .so files
692	// e.g. moduleNames["libprotobuf-cpp-full-3.9.1.so"] = "libprotobuf-cpp-full"
693	moduleNames := make(map[string]string)
694
695	var headers android.Paths
696
697	// installVndkSnapshotLib copies built .so file from the module.
698	// Also, if the build artifacts is on, write a json file which contains all exported flags
699	// with FlagExporterInfo.
700	installVndkSnapshotLib := func(m *Module, vndkType string) (android.Paths, bool) {
701		var ret android.Paths
702
703		targetArch := "arch-" + m.Target().Arch.ArchType.String()
704		if m.Target().Arch.ArchVariant != "" {
705			targetArch += "-" + m.Target().Arch.ArchVariant
706		}
707
708		libPath := m.outputFile.Path()
709		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
710		ret = append(ret, snapshot.CopyFileRule(pctx, ctx, libPath, snapshotLibOut))
711
712		// json struct to export snapshot information
713		prop := struct {
714			MinSdkVersion       string   `json:",omitempty"`
715			LicenseKinds        []string `json:",omitempty"`
716			LicenseTexts        []string `json:",omitempty"`
717			ExportedDirs        []string `json:",omitempty"`
718			ExportedSystemDirs  []string `json:",omitempty"`
719			ExportedFlags       []string `json:",omitempty"`
720			RelativeInstallPath string   `json:",omitempty"`
721		}{}
722
723		prop.LicenseKinds = m.EffectiveLicenseKinds()
724		prop.LicenseTexts = m.EffectiveLicenseFiles().Strings()
725		prop.MinSdkVersion = m.MinSdkVersion()
726
727		if ctx.Config().VndkSnapshotBuildArtifacts() {
728			exportedInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
729			prop.ExportedFlags = exportedInfo.Flags
730			prop.ExportedDirs = exportedInfo.IncludeDirs.Strings()
731			prop.ExportedSystemDirs = exportedInfo.SystemIncludeDirs.Strings()
732			prop.RelativeInstallPath = m.RelativeInstallPath()
733		}
734
735		propOut := snapshotLibOut + ".json"
736
737		j, err := json.Marshal(prop)
738		if err != nil {
739			ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
740			return nil, false
741		}
742		ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
743
744		return ret, true
745	}
746
747	ctx.VisitAllModules(func(module android.Module) {
748		m, ok := module.(*Module)
749		if !ok || !m.Enabled() {
750			return
751		}
752
753		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
754
755		vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo)
756		if !ok {
757			return
758		}
759
760		// For all snapshot candidates, the followings are captured.
761		//   - .so files
762		//   - notice files
763		//
764		// The followings are also captured if VNDK_SNAPSHOT_BUILD_ARTIFACTS.
765		//   - .json files containing exported flags
766		//   - exported headers from collectHeadersForSnapshot()
767		//
768		// Headers are deduplicated after visiting all modules.
769
770		// install .so files for appropriate modules.
771		// Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
772		libs, ok := installVndkSnapshotLib(m, vndkType)
773		if !ok {
774			return
775		}
776		snapshotOutputs = append(snapshotOutputs, libs...)
777
778		// These are for generating module_names.txt and module_paths.txt
779		stem := m.outputFile.Path().Base()
780		moduleNames[stem] = ctx.ModuleName(m)
781		modulePaths[stem] = ctx.ModuleDir(m)
782
783		for _, notice := range m.EffectiveLicenseFiles() {
784			if _, ok := noticeBuilt[notice.String()]; !ok {
785				noticeBuilt[notice.String()] = true
786				snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
787					pctx, ctx, notice, filepath.Join(noticeDir, notice.String())))
788			}
789		}
790
791		if ctx.Config().VndkSnapshotBuildArtifacts() {
792			headers = append(headers, m.SnapshotHeaders()...)
793		}
794	})
795
796	// install all headers after removing duplicates
797	for _, header := range android.FirstUniquePaths(headers) {
798		snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
799			pctx, ctx, header, filepath.Join(includeDir, header.String())))
800	}
801
802	// install *.libraries.txt except vndkcorevariant.libraries.txt
803	ctx.VisitAllModules(func(module android.Module) {
804		m, ok := module.(*vndkLibrariesTxt)
805		if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
806			return
807		}
808		snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
809			pctx, ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
810	})
811
812	/*
813		module_paths.txt contains paths on which VNDK modules are defined.
814		e.g.,
815			libbase.so system/libbase
816			libc.so bionic/libc
817			...
818	*/
819	snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, modulePaths, filepath.Join(configsDir, "module_paths.txt")))
820
821	/*
822		module_names.txt contains names as which VNDK modules are defined,
823		because output filename and module name can be different with stem and suffix properties.
824
825		e.g.,
826			libcutils.so libcutils
827			libprotobuf-cpp-full-3.9.2.so libprotobuf-cpp-full
828			...
829	*/
830	snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, moduleNames, filepath.Join(configsDir, "module_names.txt")))
831
832	// All artifacts are ready. Sort them to normalize ninja and then zip.
833	sort.Slice(snapshotOutputs, func(i, j int) bool {
834		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
835	})
836
837	zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
838	zipRule := android.NewRuleBuilder(pctx, ctx)
839
840	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
841	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
842	rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp")
843	zipRule.Command().
844		Text("tr").
845		FlagWithArg("-d ", "\\'").
846		FlagWithRspFileInputList("< ", rspFile, snapshotOutputs).
847		FlagWithOutput("> ", snapshotOutputList)
848
849	zipRule.Temporary(snapshotOutputList)
850
851	zipRule.Command().
852		BuiltTool("soong_zip").
853		FlagWithOutput("-o ", zipPath).
854		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
855		FlagWithInput("-l ", snapshotOutputList)
856
857	zipRule.Build(zipPath.String(), "vndk snapshot "+zipPath.String())
858	zipRule.DeleteTemporaryFiles()
859	c.vndkSnapshotZipFile = android.OptionalPathForPath(zipPath)
860}
861
862func getVndkFileName(m *Module) (string, error) {
863	if library, ok := m.linker.(*libraryDecorator); ok {
864		return library.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil
865	}
866	if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok {
867		return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil
868	}
869	return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker)
870}
871
872func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.SingletonContext) {
873	// Build list of vndk libs as merged & tagged & filter-out(libclang_rt):
874	// Since each target have different set of libclang_rt.* files,
875	// keep the common set of files in vndk.libraries.txt
876	_, llndk := vndkModuleListRemover(llndkLibraries, "libclang_rt.")(ctx)
877	_, vndkcore := vndkModuleListRemover(vndkCoreLibraries, "libclang_rt.")(ctx)
878	_, vndksp := vndkSPLibraries(ctx)
879	_, vndkprivate := vndkPrivateLibraries(ctx)
880	_, vndkproduct := vndkModuleListRemover(vndkProductLibraries, "libclang_rt.")(ctx)
881	var merged []string
882	merged = append(merged, addPrefix(llndk, "LLNDK: ")...)
883	merged = append(merged, addPrefix(vndksp, "VNDK-SP: ")...)
884	merged = append(merged, addPrefix(vndkcore, "VNDK-core: ")...)
885	merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...)
886	merged = append(merged, addPrefix(vndkproduct, "VNDK-product: ")...)
887	c.vndkLibrariesFile = android.PathForOutput(ctx, "vndk", "vndk.libraries.txt")
888	android.WriteFileRule(ctx, c.vndkLibrariesFile, strings.Join(merged, "\n"))
889}
890
891func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
892	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
893	// they been moved to an apex.
894	movedToApexLlndkLibraries := make(map[string]bool)
895	ctx.VisitAllModules(func(module android.Module) {
896		if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() {
897			// Skip bionic libs, they are handled in different manner
898			name := library.implementationModuleName(module.(*Module).BaseModuleName())
899			if module.(android.ApexModule).DirectlyInAnyApex() && !isBionic(name) {
900				movedToApexLlndkLibraries[name] = true
901			}
902		}
903	})
904
905	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES",
906		strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " "))
907
908	ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String())
909	ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String())
910}
911