1// Copyright (C) 2017 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package hal2vts
16
17import (
18	"path/filepath"
19	"sort"
20	"strings"
21	"sync"
22
23	"android/soong/android"
24	"android/soong/genrule"
25
26	"github.com/google/blueprint"
27)
28
29func init() {
30	android.RegisterModuleType("hal2vts", hal2vtsFactory)
31}
32
33var (
34	pctx = android.NewPackageContext("android/soong/hal2vts")
35
36	hidlGen = pctx.HostBinToolVariable("hidlGen", "hidl-gen")
37
38	hidlGenCmd = "${hidlGen}  -o ${genDir} -L vts " +
39		"-r android.hardware:hardware/interfaces " +
40		"-r android.hidl:system/libhidl/transport " +
41		"${pckg}@${ver}::${halFile}"
42
43	hal2vtsRule = pctx.StaticRule("hal2vtsRule", blueprint.RuleParams{
44		Command:     hidlGenCmd,
45		CommandDeps: []string{"${hidlGen}"},
46		Description: "hidl-gen -l vts $in => $out",
47	}, "genDir", "pckg", "ver", "halFile")
48)
49
50type hal2vtsProperties struct {
51	Srcs []string
52	Out  []string
53}
54
55type hal2vts struct {
56	android.ModuleBase
57
58	properties hal2vtsProperties
59
60	exportedHeaderDirs android.Paths
61	generatedHeaders   android.Paths
62}
63
64var _ genrule.SourceFileGenerator = (*hal2vts)(nil)
65
66func (h *hal2vts) GenerateAndroidBuildActions(ctx android.ModuleContext) {
67	// Sort by name to match .hal to .vts file name.
68	sort.Strings(h.properties.Out)
69	srcFiles := ctx.ExpandSources(h.properties.Srcs, nil)
70	sort.SliceStable(srcFiles, func(i, j int) bool {
71		return strings.Compare(srcFiles[j].String(), srcFiles[i].String()) == 1
72	})
73
74	if len(srcFiles) != len(h.properties.Out) {
75		ctx.ModuleErrorf("Number of inputs must be equal to number of outputs.")
76	}
77
78	genDir := android.PathForModuleGen(ctx, "").String()
79
80	vtsList := vtsList(ctx.AConfig())
81
82	vtsListMutex.Lock()
83	defer vtsListMutex.Unlock()
84
85	for i, src := range srcFiles {
86		out := android.PathForModuleGen(ctx, h.properties.Out[i])
87		if src.Ext() != ".hal" {
88			ctx.ModuleErrorf("Source file has to be a .hal file.")
89		}
90
91		relSrc, err := filepath.Rel("hardware/interfaces/", src.String())
92		if err != nil {
93			ctx.ModuleErrorf("Source file has to be from hardware/interfaces")
94		}
95		halDir := filepath.Dir(relSrc)
96		halFile := strings.TrimSuffix(src.Base(), ".hal")
97
98		ver := filepath.Base(halDir)
99		// Need this to transform directory path to hal name.
100		// For example, audio/effect -> audio.effect
101		pckg := strings.Replace(filepath.Dir(halDir), "/", ".", -1)
102		pckg = "android.hardware." + pckg
103
104		ctx.ModuleBuild(pctx, android.ModuleBuildParams{
105			Rule:   hal2vtsRule,
106			Input:  src,
107			Output: out,
108			Args: map[string]string{
109				"genDir":  genDir,
110				"pckg":    pckg,
111				"ver":     ver,
112				"halFile": halFile,
113			},
114		})
115		h.generatedHeaders = append(h.generatedHeaders, out)
116		*vtsList = append(*vtsList, out)
117	}
118	h.exportedHeaderDirs = append(h.exportedHeaderDirs, android.PathForModuleGen(ctx, ""))
119}
120
121func (h *hal2vts) DepsMutator(ctx android.BottomUpMutatorContext) {
122	android.ExtractSourcesDeps(ctx, h.properties.Srcs)
123}
124
125func (h *hal2vts) GeneratedHeaderDirs() android.Paths {
126	return h.exportedHeaderDirs
127}
128
129func (h *hal2vts) GeneratedSourceFiles() android.Paths {
130	return h.generatedHeaders
131}
132
133func hal2vtsFactory() (blueprint.Module, []interface{}) {
134	h := &hal2vts{}
135	return android.InitAndroidModule(h, &h.properties)
136}
137
138func vtsList(config android.Config) *android.Paths {
139	return config.Once("vtsList", func() interface{} {
140		return &android.Paths{}
141	}).(*android.Paths)
142}
143
144var vtsListMutex sync.Mutex
145
146func init() {
147	android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
148}
149
150func makeVarsProvider(ctx android.MakeVarsContext) {
151	vtsList := vtsList(ctx.Config()).Strings()
152	sort.Strings(vtsList)
153
154	ctx.Strict("VTS_SPEC_FILE_LIST", strings.Join(vtsList, " "))
155}
156