• 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) {
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
372		useCoreVariant := m.VndkVersion() == mctx.DeviceConfig().PlatformVndkVersion() &&
373			mctx.DeviceConfig().VndkUseCoreVariant() && !m.MustUseVendorVariant()
374		return lib.shared() && m.InVendor() && m.IsVndk() && !m.IsVndkExt() && !useCoreVariant
375	}
376	return false
377}
378
379// gather list of vndk-core, vndk-sp, and ll-ndk libs
380func VndkMutator(mctx android.BottomUpMutatorContext) {
381	m, ok := mctx.Module().(*Module)
382	if !ok {
383		return
384	}
385
386	if shouldSkipVndkMutator(m) {
387		return
388	}
389
390	lib, isLib := m.linker.(*libraryDecorator)
391	prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker)
392
393	if m.UseVndk() && isLib && lib.hasLLNDKStubs() {
394		m.VendorProperties.IsLLNDK = true
395		m.VendorProperties.IsVNDKPrivate = Bool(lib.Properties.Llndk.Private)
396	}
397	if m.UseVndk() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() {
398		m.VendorProperties.IsLLNDK = true
399		m.VendorProperties.IsVNDKPrivate = Bool(prebuiltLib.Properties.Llndk.Private)
400	}
401
402	if (isLib && lib.buildShared()) || (isPrebuiltLib && prebuiltLib.buildShared()) {
403		if m.vndkdep != nil && m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
404			processVndkLibrary(mctx, m)
405			return
406		}
407	}
408}
409
410func init() {
411	RegisterVndkLibraryTxtTypes(android.InitRegistrationContext)
412	android.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
413}
414
415func RegisterVndkLibraryTxtTypes(ctx android.RegistrationContext) {
416	ctx.RegisterSingletonModuleType("llndk_libraries_txt", llndkLibrariesTxtFactory)
417	ctx.RegisterSingletonModuleType("vndksp_libraries_txt", vndkSPLibrariesTxtFactory)
418	ctx.RegisterSingletonModuleType("vndkcore_libraries_txt", vndkCoreLibrariesTxtFactory)
419	ctx.RegisterSingletonModuleType("vndkprivate_libraries_txt", vndkPrivateLibrariesTxtFactory)
420	ctx.RegisterSingletonModuleType("vndkproduct_libraries_txt", vndkProductLibrariesTxtFactory)
421	ctx.RegisterSingletonModuleType("vndkcorevariant_libraries_txt", vndkUsingCoreVariantLibrariesTxtFactory)
422}
423
424type vndkLibrariesTxt struct {
425	android.SingletonModuleBase
426
427	lister               moduleListerFunc
428	makeVarName          string
429	filterOutFromMakeVar string
430
431	properties VndkLibrariesTxtProperties
432
433	outputFile  android.OutputPath
434	moduleNames []string
435	fileNames   []string
436}
437
438type VndkLibrariesTxtProperties struct {
439	Insert_vndk_version *bool
440}
441
442var _ etc.PrebuiltEtcModule = &vndkLibrariesTxt{}
443var _ android.OutputFileProducer = &vndkLibrariesTxt{}
444
445// llndk_libraries_txt is a singleton module whose content is a list of LLNDK libraries
446// generated by Soong but can be referenced by other modules.
447// For example, apex_vndk can depend on these files as prebuilt.
448// Make uses LLNDK_LIBRARIES to determine which libraries to install.
449// HWASAN is only part of the LL-NDK in builds in which libc depends on HWASAN.
450// Therefore, by removing the library here, we cause it to only be installed if libc
451// depends on it.
452func llndkLibrariesTxtFactory() android.SingletonModule {
453	return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan")
454}
455
456// vndksp_libraries_txt is a singleton module whose content is a list of VNDKSP libraries
457// generated by Soong but can be referenced by other modules.
458// For example, apex_vndk can depend on these files as prebuilt.
459func vndkSPLibrariesTxtFactory() android.SingletonModule {
460	return newVndkLibrariesTxt(vndkSPLibraries, "VNDK_SAMEPROCESS_LIBRARIES")
461}
462
463// vndkcore_libraries_txt is a singleton module whose content is a list of VNDK core libraries
464// generated by Soong but can be referenced by other modules.
465// For example, apex_vndk can depend on these files as prebuilt.
466func vndkCoreLibrariesTxtFactory() android.SingletonModule {
467	return newVndkLibrariesTxt(vndkCoreLibraries, "VNDK_CORE_LIBRARIES")
468}
469
470// vndkprivate_libraries_txt is a singleton module whose content is a list of VNDK private libraries
471// generated by Soong but can be referenced by other modules.
472// For example, apex_vndk can depend on these files as prebuilt.
473func vndkPrivateLibrariesTxtFactory() android.SingletonModule {
474	return newVndkLibrariesTxt(vndkPrivateLibraries, "VNDK_PRIVATE_LIBRARIES")
475}
476
477// vndkproduct_libraries_txt is a singleton module whose content is a list of VNDK product libraries
478// generated by Soong but can be referenced by other modules.
479// For example, apex_vndk can depend on these files as prebuilt.
480func vndkProductLibrariesTxtFactory() android.SingletonModule {
481	return newVndkLibrariesTxt(vndkProductLibraries, "VNDK_PRODUCT_LIBRARIES")
482}
483
484// vndkcorevariant_libraries_txt is a singleton module whose content is a list of VNDK libraries
485// that are using the core variant, generated by Soong but can be referenced by other modules.
486// For example, apex_vndk can depend on these files as prebuilt.
487func vndkUsingCoreVariantLibrariesTxtFactory() android.SingletonModule {
488	return newVndkLibrariesTxt(vndkUsingCoreVariantLibraries, "VNDK_USING_CORE_VARIANT_LIBRARIES")
489}
490
491func newVndkLibrariesWithMakeVarFilter(lister moduleListerFunc, makeVarName string, filter string) android.SingletonModule {
492	m := &vndkLibrariesTxt{
493		lister:               lister,
494		makeVarName:          makeVarName,
495		filterOutFromMakeVar: filter,
496	}
497	m.AddProperties(&m.properties)
498	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
499	return m
500}
501
502func newVndkLibrariesTxt(lister moduleListerFunc, makeVarName string) android.SingletonModule {
503	return newVndkLibrariesWithMakeVarFilter(lister, makeVarName, "")
504}
505
506func insertVndkVersion(filename string, vndkVersion string) string {
507	if index := strings.LastIndex(filename, "."); index != -1 {
508		return filename[:index] + "." + vndkVersion + filename[index:]
509	}
510	return filename
511}
512
513func (txt *vndkLibrariesTxt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
514	var filename string
515	if BoolDefault(txt.properties.Insert_vndk_version, true) {
516		filename = insertVndkVersion(txt.Name(), ctx.DeviceConfig().PlatformVndkVersion())
517	} else {
518		filename = txt.Name()
519	}
520
521	txt.outputFile = android.PathForModuleOut(ctx, filename).OutputPath
522
523	installPath := android.PathForModuleInstall(ctx, "etc")
524	ctx.InstallFile(installPath, filename, txt.outputFile)
525}
526
527func (txt *vndkLibrariesTxt) GenerateSingletonBuildActions(ctx android.SingletonContext) {
528	txt.moduleNames, txt.fileNames = txt.lister(ctx)
529	android.WriteFileRule(ctx, txt.outputFile, strings.Join(txt.fileNames, "\n"))
530}
531
532func (txt *vndkLibrariesTxt) AndroidMkEntries() []android.AndroidMkEntries {
533	return []android.AndroidMkEntries{android.AndroidMkEntries{
534		Class:      "ETC",
535		OutputFile: android.OptionalPathForPath(txt.outputFile),
536		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
537			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
538				entries.SetString("LOCAL_MODULE_STEM", txt.outputFile.Base())
539			},
540		},
541	}}
542}
543
544func (txt *vndkLibrariesTxt) MakeVars(ctx android.MakeVarsContext) {
545	filter := func(modules []string, prefix string) []string {
546		if prefix == "" {
547			return modules
548		}
549		var result []string
550		for _, module := range modules {
551			if strings.HasPrefix(module, prefix) {
552				continue
553			} else {
554				result = append(result, module)
555			}
556		}
557		return result
558	}
559	ctx.Strict(txt.makeVarName, strings.Join(filter(txt.moduleNames, txt.filterOutFromMakeVar), " "))
560}
561
562// PrebuiltEtcModule interface
563func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath {
564	return txt.outputFile
565}
566
567// PrebuiltEtcModule interface
568func (txt *vndkLibrariesTxt) BaseDir() string {
569	return "etc"
570}
571
572// PrebuiltEtcModule interface
573func (txt *vndkLibrariesTxt) SubDir() string {
574	return ""
575}
576
577func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
578	return android.Paths{txt.outputFile}, nil
579}
580
581func VndkSnapshotSingleton() android.Singleton {
582	return &vndkSnapshotSingleton{}
583}
584
585type vndkSnapshotSingleton struct {
586	vndkLibrariesFile   android.OutputPath
587	vndkSnapshotZipFile android.OptionalPath
588}
589
590func isVndkSnapshotAware(config android.DeviceConfig, m LinkableInterface,
591	apexInfo android.ApexInfo) (vndkType string, isVndkSnapshotLib bool) {
592
593	if m.Target().NativeBridge == android.NativeBridgeEnabled {
594		return "", false
595	}
596	// !inVendor: There's product/vendor variants for VNDK libs. We only care about vendor variants.
597	// !installable: Snapshot only cares about "installable" modules.
598	// !m.IsLlndk: llndk stubs are required for building against snapshots.
599	// IsSnapshotPrebuilt: Snapshotting a snapshot doesn't make sense.
600	// !outputFile.Valid: Snapshot requires valid output file.
601	if !m.InVendor() || (!installable(m, apexInfo) && !m.IsLlndk()) || m.IsSnapshotPrebuilt() || !m.OutputFile().Valid() {
602		return "", false
603	}
604	if !m.IsSnapshotLibrary() || !m.Shared() {
605		return "", false
606	}
607	if m.VndkVersion() == config.PlatformVndkVersion() {
608		if m.IsVndk() && !m.IsVndkExt() {
609			if m.IsVndkSp() {
610				return "vndk-sp", true
611			} else {
612				return "vndk-core", true
613			}
614		} else if m.HasLlndkStubs() && m.StubsVersion() == "" {
615			// Use default version for the snapshot.
616			return "llndk-stub", true
617		}
618	}
619
620	return "", false
621}
622
623func (c *vndkSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
624	// build these files even if PlatformVndkVersion or BoardVndkVersion is not set
625	c.buildVndkLibrariesTxtFiles(ctx)
626
627	// BOARD_VNDK_VERSION must be set to 'current' in order to generate a VNDK snapshot.
628	if ctx.DeviceConfig().VndkVersion() != "current" {
629		return
630	}
631
632	if ctx.DeviceConfig().PlatformVndkVersion() == "" {
633		return
634	}
635
636	var snapshotOutputs android.Paths
637
638	/*
639		VNDK snapshot zipped artifacts directory structure:
640		{SNAPSHOT_ARCH}/
641			arch-{TARGET_ARCH}-{TARGET_ARCH_VARIANT}/
642				shared/
643					vndk-core/
644						(VNDK-core libraries, e.g. libbinder.so)
645					vndk-sp/
646						(VNDK-SP libraries, e.g. libc++.so)
647					llndk-stub/
648						(LLNDK stub libraries)
649			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_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			binder32/
658				(This directory is newly introduced in v28 (Android P) to hold
659				prebuilts built for 32-bit binder interface.)
660				arch-{TARGET_ARCH}-{TARGE_ARCH_VARIANT}/
661					...
662			configs/
663				(various *.txt configuration files)
664			include/
665				(header files of same directory structure with source tree)
666			NOTICE_FILES/
667				(notice files of libraries, e.g. libcutils.so.txt)
668	*/
669
670	snapshotDir := "vndk-snapshot"
671	snapshotArchDir := filepath.Join(snapshotDir, ctx.DeviceConfig().DeviceArch())
672
673	configsDir := filepath.Join(snapshotArchDir, "configs")
674	noticeDir := filepath.Join(snapshotArchDir, "NOTICE_FILES")
675	includeDir := filepath.Join(snapshotArchDir, "include")
676
677	// set of notice files copied.
678	noticeBuilt := make(map[string]bool)
679
680	// paths of VNDK modules for GPL license checking
681	modulePaths := make(map[string]string)
682
683	// actual module names of .so files
684	// e.g. moduleNames["libprotobuf-cpp-full-3.9.1.so"] = "libprotobuf-cpp-full"
685	moduleNames := make(map[string]string)
686
687	var headers android.Paths
688
689	// installVndkSnapshotLib copies built .so file from the module.
690	// Also, if the build artifacts is on, write a json file which contains all exported flags
691	// with FlagExporterInfo.
692	installVndkSnapshotLib := func(m *Module, vndkType string) (android.Paths, bool) {
693		var ret android.Paths
694
695		targetArch := "arch-" + m.Target().Arch.ArchType.String()
696		if m.Target().Arch.ArchVariant != "" {
697			targetArch += "-" + m.Target().Arch.ArchVariant
698		}
699
700		libPath := m.outputFile.Path()
701		snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, "shared", vndkType, libPath.Base())
702		ret = append(ret, snapshot.CopyFileRule(pctx, ctx, libPath, snapshotLibOut))
703
704		if ctx.Config().VndkSnapshotBuildArtifacts() {
705			prop := struct {
706				ExportedDirs        []string `json:",omitempty"`
707				ExportedSystemDirs  []string `json:",omitempty"`
708				ExportedFlags       []string `json:",omitempty"`
709				RelativeInstallPath string   `json:",omitempty"`
710			}{}
711			exportedInfo := ctx.ModuleProvider(m, FlagExporterInfoProvider).(FlagExporterInfo)
712			prop.ExportedFlags = exportedInfo.Flags
713			prop.ExportedDirs = exportedInfo.IncludeDirs.Strings()
714			prop.ExportedSystemDirs = exportedInfo.SystemIncludeDirs.Strings()
715			prop.RelativeInstallPath = m.RelativeInstallPath()
716
717			propOut := snapshotLibOut + ".json"
718
719			j, err := json.Marshal(prop)
720			if err != nil {
721				ctx.Errorf("json marshal to %q failed: %#v", propOut, err)
722				return nil, false
723			}
724			ret = append(ret, snapshot.WriteStringToFileRule(ctx, string(j), propOut))
725		}
726		return ret, true
727	}
728
729	ctx.VisitAllModules(func(module android.Module) {
730		m, ok := module.(*Module)
731		if !ok || !m.Enabled() {
732			return
733		}
734
735		apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
736
737		vndkType, ok := isVndkSnapshotAware(ctx.DeviceConfig(), m, apexInfo)
738		if !ok {
739			return
740		}
741
742		// For all snapshot candidates, the followings are captured.
743		//   - .so files
744		//   - notice files
745		//
746		// The followings are also captured if VNDK_SNAPSHOT_BUILD_ARTIFACTS.
747		//   - .json files containing exported flags
748		//   - exported headers from collectHeadersForSnapshot()
749		//
750		// Headers are deduplicated after visiting all modules.
751
752		// install .so files for appropriate modules.
753		// Also install .json files if VNDK_SNAPSHOT_BUILD_ARTIFACTS
754		libs, ok := installVndkSnapshotLib(m, vndkType)
755		if !ok {
756			return
757		}
758		snapshotOutputs = append(snapshotOutputs, libs...)
759
760		// These are for generating module_names.txt and module_paths.txt
761		stem := m.outputFile.Path().Base()
762		moduleNames[stem] = ctx.ModuleName(m)
763		modulePaths[stem] = ctx.ModuleDir(m)
764
765		if len(m.NoticeFiles()) > 0 {
766			noticeName := stem + ".txt"
767			// skip already copied notice file
768			if _, ok := noticeBuilt[noticeName]; !ok {
769				noticeBuilt[noticeName] = true
770				snapshotOutputs = append(snapshotOutputs, combineNoticesRule(
771					ctx, m.NoticeFiles(), filepath.Join(noticeDir, noticeName)))
772			}
773		}
774
775		if ctx.Config().VndkSnapshotBuildArtifacts() {
776			headers = append(headers, m.SnapshotHeaders()...)
777		}
778	})
779
780	// install all headers after removing duplicates
781	for _, header := range android.FirstUniquePaths(headers) {
782		snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
783			pctx, ctx, header, filepath.Join(includeDir, header.String())))
784	}
785
786	// install *.libraries.txt except vndkcorevariant.libraries.txt
787	ctx.VisitAllModules(func(module android.Module) {
788		m, ok := module.(*vndkLibrariesTxt)
789		if !ok || !m.Enabled() || m.Name() == vndkUsingCoreVariantLibrariesTxt {
790			return
791		}
792		snapshotOutputs = append(snapshotOutputs, snapshot.CopyFileRule(
793			pctx, ctx, m.OutputFile(), filepath.Join(configsDir, m.Name())))
794	})
795
796	/*
797		module_paths.txt contains paths on which VNDK modules are defined.
798		e.g.,
799			libbase.so system/libbase
800			libc.so bionic/libc
801			...
802	*/
803	snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, modulePaths, filepath.Join(configsDir, "module_paths.txt")))
804
805	/*
806		module_names.txt contains names as which VNDK modules are defined,
807		because output filename and module name can be different with stem and suffix properties.
808
809		e.g.,
810			libcutils.so libcutils
811			libprotobuf-cpp-full-3.9.2.so libprotobuf-cpp-full
812			...
813	*/
814	snapshotOutputs = append(snapshotOutputs, installMapListFileRule(ctx, moduleNames, filepath.Join(configsDir, "module_names.txt")))
815
816	// All artifacts are ready. Sort them to normalize ninja and then zip.
817	sort.Slice(snapshotOutputs, func(i, j int) bool {
818		return snapshotOutputs[i].String() < snapshotOutputs[j].String()
819	})
820
821	zipPath := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+".zip")
822	zipRule := android.NewRuleBuilder(pctx, ctx)
823
824	// filenames in rspfile from FlagWithRspFileInputList might be single-quoted. Remove it with tr
825	snapshotOutputList := android.PathForOutput(ctx, snapshotDir, "android-vndk-"+ctx.DeviceConfig().DeviceArch()+"_list")
826	rspFile := snapshotOutputList.ReplaceExtension(ctx, "rsp")
827	zipRule.Command().
828		Text("tr").
829		FlagWithArg("-d ", "\\'").
830		FlagWithRspFileInputList("< ", rspFile, snapshotOutputs).
831		FlagWithOutput("> ", snapshotOutputList)
832
833	zipRule.Temporary(snapshotOutputList)
834
835	zipRule.Command().
836		BuiltTool("soong_zip").
837		FlagWithOutput("-o ", zipPath).
838		FlagWithArg("-C ", android.PathForOutput(ctx, snapshotDir).String()).
839		FlagWithInput("-l ", snapshotOutputList)
840
841	zipRule.Build(zipPath.String(), "vndk snapshot "+zipPath.String())
842	zipRule.DeleteTemporaryFiles()
843	c.vndkSnapshotZipFile = android.OptionalPathForPath(zipPath)
844}
845
846func getVndkFileName(m *Module) (string, error) {
847	if library, ok := m.linker.(*libraryDecorator); ok {
848		return library.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil
849	}
850	if prebuilt, ok := m.linker.(*prebuiltLibraryLinker); ok {
851		return prebuilt.libraryDecorator.getLibNameHelper(m.BaseModuleName(), true, false) + ".so", nil
852	}
853	return "", fmt.Errorf("VNDK library should have libraryDecorator or prebuiltLibraryLinker as linker: %T", m.linker)
854}
855
856func (c *vndkSnapshotSingleton) buildVndkLibrariesTxtFiles(ctx android.SingletonContext) {
857	// Build list of vndk libs as merged & tagged & filter-out(libclang_rt):
858	// Since each target have different set of libclang_rt.* files,
859	// keep the common set of files in vndk.libraries.txt
860	_, llndk := vndkModuleListRemover(llndkLibraries, "libclang_rt.")(ctx)
861	_, vndkcore := vndkModuleListRemover(vndkCoreLibraries, "libclang_rt.")(ctx)
862	_, vndksp := vndkSPLibraries(ctx)
863	_, vndkprivate := vndkPrivateLibraries(ctx)
864	_, vndkproduct := vndkModuleListRemover(vndkProductLibraries, "libclang_rt.")(ctx)
865	var merged []string
866	merged = append(merged, addPrefix(llndk, "LLNDK: ")...)
867	merged = append(merged, addPrefix(vndksp, "VNDK-SP: ")...)
868	merged = append(merged, addPrefix(vndkcore, "VNDK-core: ")...)
869	merged = append(merged, addPrefix(vndkprivate, "VNDK-private: ")...)
870	merged = append(merged, addPrefix(vndkproduct, "VNDK-product: ")...)
871	c.vndkLibrariesFile = android.PathForOutput(ctx, "vndk", "vndk.libraries.txt")
872	android.WriteFileRule(ctx, c.vndkLibrariesFile, strings.Join(merged, "\n"))
873}
874
875func (c *vndkSnapshotSingleton) MakeVars(ctx android.MakeVarsContext) {
876	// Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to avoid installing libraries on /system if
877	// they been moved to an apex.
878	movedToApexLlndkLibraries := make(map[string]bool)
879	ctx.VisitAllModules(func(module android.Module) {
880		if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() {
881			// Skip bionic libs, they are handled in different manner
882			name := library.implementationModuleName(module.(*Module).BaseModuleName())
883			if module.(android.ApexModule).DirectlyInAnyApex() && !isBionic(name) {
884				movedToApexLlndkLibraries[name] = true
885			}
886		}
887	})
888
889	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES",
890		strings.Join(android.SortedStringKeys(movedToApexLlndkLibraries), " "))
891
892	ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String())
893	ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String())
894}
895