1// Copyright 2019 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 java
16
17import (
18	"android/soong/android"
19	"fmt"
20)
21
22func init() {
23	android.RegisterSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
24	android.RegisterModuleType("platform_compat_config", PlatformCompatConfigFactory)
25	android.RegisterModuleType("global_compat_config", globalCompatConfigFactory)
26}
27
28func platformCompatConfigPath(ctx android.PathContext) android.OutputPath {
29	return android.PathForOutput(ctx, "compat_config", "merged_compat_config.xml")
30}
31
32type platformCompatConfigSingleton struct {
33	metadata android.Path
34}
35
36type platformCompatConfigProperties struct {
37	Src *string `android:"path"`
38}
39
40type platformCompatConfig struct {
41	android.ModuleBase
42
43	properties     platformCompatConfigProperties
44	installDirPath android.InstallPath
45	configFile     android.OutputPath
46	metadataFile   android.OutputPath
47}
48
49func (p *platformCompatConfig) compatConfigMetadata() android.OutputPath {
50	return p.metadataFile
51}
52
53func (p *platformCompatConfig) CompatConfig() android.OutputPath {
54	return p.configFile
55}
56
57func (p *platformCompatConfig) SubDir() string {
58	return "compatconfig"
59}
60
61type PlatformCompatConfigIntf interface {
62	android.Module
63
64	compatConfigMetadata() android.OutputPath
65	CompatConfig() android.OutputPath
66	// Sub dir under etc dir.
67	SubDir() string
68}
69
70var _ PlatformCompatConfigIntf = (*platformCompatConfig)(nil)
71
72// compat singleton rules
73func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
74
75	var compatConfigMetadata android.Paths
76
77	ctx.VisitAllModules(func(module android.Module) {
78		if c, ok := module.(PlatformCompatConfigIntf); ok {
79			metadata := c.compatConfigMetadata()
80			compatConfigMetadata = append(compatConfigMetadata, metadata)
81		}
82	})
83
84	if compatConfigMetadata == nil {
85		// nothing to do.
86		return
87	}
88
89	rule := android.NewRuleBuilder()
90	outputPath := platformCompatConfigPath(ctx)
91
92	rule.Command().
93		BuiltTool(ctx, "process-compat-config").
94		FlagForEachInput("--xml ", compatConfigMetadata).
95		FlagWithOutput("--merged-config ", outputPath)
96
97	rule.Build(pctx, ctx, "merged-compat-config", "Merge compat config")
98
99	p.metadata = outputPath
100}
101
102func (p *platformCompatConfigSingleton) MakeVars(ctx android.MakeVarsContext) {
103	if p.metadata != nil {
104		ctx.Strict("INTERNAL_PLATFORM_MERGED_COMPAT_CONFIG", p.metadata.String())
105	}
106}
107
108func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
109	rule := android.NewRuleBuilder()
110
111	configFileName := p.Name() + ".xml"
112	metadataFileName := p.Name() + "_meta.xml"
113	p.configFile = android.PathForModuleOut(ctx, configFileName).OutputPath
114	p.metadataFile = android.PathForModuleOut(ctx, metadataFileName).OutputPath
115	path := android.PathForModuleSrc(ctx, String(p.properties.Src))
116
117	rule.Command().
118		BuiltTool(ctx, "process-compat-config").
119		FlagWithInput("--jar ", path).
120		FlagWithOutput("--device-config ", p.configFile).
121		FlagWithOutput("--merged-config ", p.metadataFile)
122
123	p.installDirPath = android.PathForModuleInstall(ctx, "etc", "compatconfig")
124	rule.Build(pctx, ctx, configFileName, "Extract compat/compat_config.xml and install it")
125
126}
127
128func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries {
129	return []android.AndroidMkEntries{android.AndroidMkEntries{
130		Class:      "ETC",
131		OutputFile: android.OptionalPathForPath(p.configFile),
132		Include:    "$(BUILD_PREBUILT)",
133		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
134			func(entries *android.AndroidMkEntries) {
135				entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
136				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.configFile.Base())
137			},
138		},
139	}}
140}
141
142func platformCompatConfigSingletonFactory() android.Singleton {
143	return &platformCompatConfigSingleton{}
144}
145
146func PlatformCompatConfigFactory() android.Module {
147	module := &platformCompatConfig{}
148	module.AddProperties(&module.properties)
149	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
150	return module
151}
152
153//============== merged_compat_config =================
154type globalCompatConfigProperties struct {
155	// name of the file into which the metadata will be copied.
156	Filename *string
157}
158
159type globalCompatConfig struct {
160	android.ModuleBase
161
162	properties globalCompatConfigProperties
163
164	outputFilePath android.OutputPath
165}
166
167func (c *globalCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
168	filename := String(c.properties.Filename)
169
170	inputPath := platformCompatConfigPath(ctx)
171	c.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
172
173	// This ensures that outputFilePath has the correct name for others to
174	// use, as the source file may have a different name.
175	ctx.Build(pctx, android.BuildParams{
176		Rule:   android.Cp,
177		Output: c.outputFilePath,
178		Input:  inputPath,
179	})
180}
181
182func (h *globalCompatConfig) OutputFiles(tag string) (android.Paths, error) {
183	switch tag {
184	case "":
185		return android.Paths{h.outputFilePath}, nil
186	default:
187		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
188	}
189}
190
191// global_compat_config provides access to the merged compat config xml file generated by the build.
192func globalCompatConfigFactory() android.Module {
193	module := &globalCompatConfig{}
194	module.AddProperties(&module.properties)
195	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
196	return module
197}
198