• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2021 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 aidl
16
17import (
18	"android/soong/android"
19
20	"fmt"
21	"strings"
22
23	"github.com/google/blueprint"
24	"github.com/google/blueprint/proptools"
25)
26
27var (
28	aidlMetadataRule = pctx.StaticRule("aidlMetadataRule", blueprint.RuleParams{
29		Command: `rm -f ${out} && { ` +
30			`echo '{' && ` +
31			`echo "\"name\": \"${name}\"," && ` +
32			`echo "\"stability\": \"${stability}\"," && ` +
33			`echo "\"types\": [${types}]," && ` +
34			`echo "\"hashes\": [${hashes}]," && ` +
35			`echo "\"has_development\": ${has_development}," && ` +
36			`echo "\"versions\": [${versions}]" && ` +
37			`echo '}' ` +
38			`;} >> ${out}`,
39		Description: "AIDL metadata: ${out}",
40	}, "name", "stability", "types", "hashes", "has_development", "versions")
41
42	joinJsonObjectsToArrayRule = pctx.StaticRule("joinJsonObjectsToArrayRule", blueprint.RuleParams{
43		Rspfile:        "$out.rsp",
44		RspfileContent: "$files",
45		Command: "rm -rf ${out} && " +
46			// Start the output array with an opening bracket.
47			"echo '[' >> ${out} && " +
48			// Append each input file and a comma to the output.
49			"for file in $$(cat ${out}.rsp); do " +
50			"cat $$file >> ${out}; echo ',' >> ${out}; " +
51			"done && " +
52			// Remove the last comma, replacing it with the closing bracket.
53			"sed -i '$$d' ${out} && echo ']' >> ${out}",
54		Description: "Joining JSON objects into array ${out}",
55	}, "files")
56)
57
58func init() {
59	android.RegisterModuleType("aidl_interfaces_metadata", aidlInterfacesMetadataSingletonFactory)
60}
61
62func aidlInterfacesMetadataSingletonFactory() android.Module {
63	i := &aidlInterfacesMetadataSingleton{}
64	android.InitAndroidModule(i)
65	return i
66}
67
68type aidlInterfacesMetadataSingleton struct {
69	android.ModuleBase
70
71	metadataPath android.WritablePath
72}
73
74var _ android.OutputFileProducer = (*aidlInterfacesMetadataSingleton)(nil)
75
76func (m *aidlInterfacesMetadataSingleton) GenerateAndroidBuildActions(ctx android.ModuleContext) {
77	if m.Name() != aidlMetadataSingletonName {
78		ctx.PropertyErrorf("name", "must be %s", aidlMetadataSingletonName)
79		return
80	}
81
82	type ModuleInfo struct {
83		Stability      string
84		ComputedTypes  []string
85		HashFiles      []string
86		HasDevelopment android.WritablePath
87		Versions       []string
88	}
89
90	// name -> ModuleInfo
91	moduleInfos := map[string]ModuleInfo{}
92	ctx.VisitDirectDeps(func(m android.Module) {
93		if !m.ExportedToMake() {
94			return
95		}
96
97		switch t := m.(type) {
98		case *aidlInterface:
99			info := moduleInfos[t.ModuleBase.Name()]
100			info.Stability = proptools.StringDefault(t.properties.Stability, "")
101			info.ComputedTypes = t.computedTypes
102			info.Versions = t.getVersions()
103			moduleInfos[t.ModuleBase.Name()] = info
104		case *aidlGenRule:
105			info := moduleInfos[t.properties.BaseName]
106			if t.hashFile != nil {
107				info.HashFiles = append(info.HashFiles, t.hashFile.String())
108			}
109			moduleInfos[t.properties.BaseName] = info
110		case *aidlApi:
111			info := moduleInfos[t.properties.BaseName]
112			info.HasDevelopment = t.hasDevelopment
113			moduleInfos[t.properties.BaseName] = info
114		}
115
116	})
117
118	var metadataOutputs android.Paths
119	for _, name := range android.SortedStringKeys(moduleInfos) {
120		info := moduleInfos[name]
121		metadataPath := android.PathForModuleOut(ctx, "metadata_"+name)
122		metadataOutputs = append(metadataOutputs, metadataPath)
123
124		// There is one aidlGenRule per-version per-backend. If we had
125		// objects per version and sub-objects per backend, we could
126		// avoid needing to filter out duplicates.
127		info.HashFiles = android.FirstUniqueStrings(info.HashFiles)
128		readHashes := ""
129		if len(info.HashFiles) > 0 {
130			readHashes = "$$(sed 's/.*/\"&\",/' " + strings.Join(info.HashFiles, " ") +
131				"| tr '\\n' ' ' | sed 's/, $$//')"
132		}
133
134		implicits := android.PathsForSource(ctx, info.HashFiles)
135		hasDevelopmentValue := "true"
136		if info.HasDevelopment != nil {
137			hasDevelopmentValue = "$$(if [ \"$$(cat " + info.HasDevelopment.String() +
138				")\" = \"1\" ]; then echo true; else echo false; fi)"
139		}
140
141		ctx.Build(pctx, android.BuildParams{
142			Rule:      aidlMetadataRule,
143			Implicits: implicits,
144			Input:     info.HasDevelopment,
145			Output:    metadataPath,
146			Args: map[string]string{
147				"name":            name,
148				"stability":       info.Stability,
149				"types":           strings.Join(wrap(`\"`, info.ComputedTypes, `\"`), ", "),
150				"hashes":          readHashes,
151				"has_development": hasDevelopmentValue,
152				"versions":        strings.Join(info.Versions, ", "),
153			},
154		})
155	}
156
157	m.metadataPath = android.PathForModuleOut(ctx, "aidl_metadata.json")
158
159	ctx.Build(pctx, android.BuildParams{
160		Rule:   joinJsonObjectsToArrayRule,
161		Inputs: metadataOutputs,
162		Output: m.metadataPath,
163		Args: map[string]string{
164			"files": strings.Join(metadataOutputs.Strings(), " "),
165		},
166	})
167}
168
169func (m *aidlInterfacesMetadataSingleton) OutputFiles(tag string) (android.Paths, error) {
170	if tag != "" {
171		return nil, fmt.Errorf("unsupported tag %q", tag)
172	}
173
174	return android.Paths{m.metadataPath}, nil
175}
176