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 "path/filepath" 19 20 "android/soong/android" 21 22 "github.com/google/blueprint" 23 "github.com/google/blueprint/proptools" 24) 25 26func init() { 27 registerPlatformCompatConfigBuildComponents(android.InitRegistrationContext) 28 29 android.RegisterSdkMemberType(CompatConfigSdkMemberType) 30} 31 32var CompatConfigSdkMemberType = &compatConfigMemberType{ 33 SdkMemberTypeBase: android.SdkMemberTypeBase{ 34 PropertyName: "compat_configs", 35 SupportsSdk: true, 36 }, 37} 38 39func registerPlatformCompatConfigBuildComponents(ctx android.RegistrationContext) { 40 ctx.RegisterParallelSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory) 41 ctx.RegisterModuleType("platform_compat_config", PlatformCompatConfigFactory) 42 ctx.RegisterModuleType("prebuilt_platform_compat_config", prebuiltCompatConfigFactory) 43 ctx.RegisterModuleType("global_compat_config", globalCompatConfigFactory) 44} 45 46type PlatformCompatConfigInfo struct { 47 CompatConfig android.OutputPath 48 SubDir string 49} 50 51var PlatformCompatConfigInfoProvider = blueprint.NewProvider[PlatformCompatConfigInfo]() 52 53var PrepareForTestWithPlatformCompatConfig = android.FixtureRegisterWithContext(registerPlatformCompatConfigBuildComponents) 54 55func platformCompatConfigPath(ctx android.PathContext) android.OutputPath { 56 return android.PathForOutput(ctx, "compat_config", "merged_compat_config.xml") 57} 58 59type platformCompatConfigProperties struct { 60 Src *string `android:"path"` 61 62 // If true, we include it in the "merged" XML (merged_compat_config.xml). 63 // Default is true. 64 Include_in_merged_xml *bool 65} 66 67type platformCompatConfig struct { 68 android.ModuleBase 69 70 properties platformCompatConfigProperties 71 installDirPath android.InstallPath 72 configFile android.OutputPath 73 metadataFile android.OutputPath 74 doMerge bool 75 76 installConfigFile android.InstallPath 77} 78 79func (p *platformCompatConfig) compatConfigMetadata() android.Path { 80 return p.metadataFile 81} 82 83func (p *platformCompatConfig) includeInMergedXml() bool { 84 return p.doMerge 85} 86 87func (p *platformCompatConfig) CompatConfig() android.OutputPath { 88 return p.configFile 89} 90 91func (p *platformCompatConfig) SubDir() string { 92 return "compatconfig" 93} 94 95type platformCompatConfigMetadataProvider interface { 96 compatConfigMetadata() android.Path 97 98 // Whether to include it in the "merged" XML (merged_compat_config.xml) or not. 99 includeInMergedXml() bool 100} 101 102type PlatformCompatConfigMetadataInfo struct { 103 CompatConfigMetadata android.Path 104 // Whether to include it in the "merged" XML (merged_compat_config.xml) or not. 105 IncludeInMergedXml bool 106} 107 108var PlatformCompatConfigMetadataInfoProvider = blueprint.NewProvider[PlatformCompatConfigMetadataInfo]() 109 110type PlatformCompatConfigIntf interface { 111 android.Module 112 113 CompatConfig() android.OutputPath 114 // Sub dir under etc dir. 115 SubDir() string 116} 117 118var _ PlatformCompatConfigIntf = (*platformCompatConfig)(nil) 119var _ platformCompatConfigMetadataProvider = (*platformCompatConfig)(nil) 120 121func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { 122 rule := android.NewRuleBuilder(pctx, ctx) 123 124 configFileName := p.Name() + ".xml" 125 metadataFileName := p.Name() + "_meta.xml" 126 p.configFile = android.PathForModuleOut(ctx, configFileName).OutputPath 127 p.metadataFile = android.PathForModuleOut(ctx, metadataFileName).OutputPath 128 p.doMerge = proptools.BoolDefault(p.properties.Include_in_merged_xml, true) 129 path := android.PathForModuleSrc(ctx, String(p.properties.Src)) 130 131 rule.Command(). 132 BuiltTool("process-compat-config"). 133 FlagWithInput("--jar ", path). 134 FlagWithOutput("--device-config ", p.configFile). 135 FlagWithOutput("--merged-config ", p.metadataFile) 136 137 p.installDirPath = android.PathForModuleInstall(ctx, "etc", "compatconfig") 138 p.installConfigFile = android.PathForModuleInstall(ctx, "etc", "compatconfig", p.configFile.Base()) 139 rule.Build(configFileName, "Extract compat/compat_config.xml and install it") 140 ctx.InstallFile(p.installDirPath, p.configFile.Base(), p.configFile) 141 ctx.SetOutputFiles(android.Paths{p.configFile}, "") 142 143 android.SetProvider(ctx, PlatformCompatConfigInfoProvider, PlatformCompatConfigInfo{ 144 CompatConfig: p.CompatConfig(), 145 SubDir: p.SubDir(), 146 }) 147 148 android.SetProvider(ctx, PlatformCompatConfigMetadataInfoProvider, PlatformCompatConfigMetadataInfo{ 149 CompatConfigMetadata: p.compatConfigMetadata(), 150 IncludeInMergedXml: p.includeInMergedXml(), 151 }) 152} 153 154func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries { 155 return []android.AndroidMkEntries{android.AndroidMkEntries{ 156 Class: "ETC", 157 OutputFile: android.OptionalPathForPath(p.configFile), 158 }} 159} 160 161func PlatformCompatConfigFactory() android.Module { 162 module := &platformCompatConfig{} 163 module.AddProperties(&module.properties) 164 android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) 165 return module 166} 167 168type compatConfigMemberType struct { 169 android.SdkMemberTypeBase 170} 171 172func (b *compatConfigMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) { 173 ctx.AddVariationDependencies(nil, dependencyTag, names...) 174} 175 176func (b *compatConfigMemberType) IsInstance(module android.Module) bool { 177 _, ok := module.(*platformCompatConfig) 178 return ok 179} 180 181func (b *compatConfigMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { 182 return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_platform_compat_config") 183} 184 185func (b *compatConfigMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties { 186 return &compatConfigSdkMemberProperties{} 187} 188 189type compatConfigSdkMemberProperties struct { 190 android.SdkMemberPropertiesBase 191 192 Metadata android.Path 193} 194 195func (b *compatConfigSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { 196 module := variant.(*platformCompatConfig) 197 b.Metadata = module.metadataFile 198} 199 200func (b *compatConfigSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { 201 builder := ctx.SnapshotBuilder() 202 if b.Metadata != nil { 203 snapshotRelativePath := filepath.Join("compat_configs", ctx.Name(), b.Metadata.Base()) 204 builder.CopyToSnapshot(b.Metadata, snapshotRelativePath) 205 propertySet.AddProperty("metadata", snapshotRelativePath) 206 } 207} 208 209var _ android.SdkMemberType = (*compatConfigMemberType)(nil) 210 211// A prebuilt version of the platform compat config module. 212type prebuiltCompatConfigModule struct { 213 android.ModuleBase 214 prebuilt android.Prebuilt 215 216 properties prebuiltCompatConfigProperties 217 218 metadataFile android.Path 219} 220 221type prebuiltCompatConfigProperties struct { 222 Metadata *string `android:"path"` 223 224 // Name of the source soong module that gets shadowed by this prebuilt 225 // If unspecified, follows the naming convention that the source module of 226 // the prebuilt is Name() without "prebuilt_" prefix 227 Source_module_name *string 228} 229 230func (module *prebuiltCompatConfigModule) Prebuilt() *android.Prebuilt { 231 return &module.prebuilt 232} 233 234func (module *prebuiltCompatConfigModule) Name() string { 235 return module.prebuilt.Name(module.ModuleBase.Name()) 236} 237 238func (module *prebuiltCompatConfigModule) compatConfigMetadata() android.Path { 239 return module.metadataFile 240} 241 242func (module *prebuiltCompatConfigModule) includeInMergedXml() bool { 243 return true // Always include in merged.xml 244} 245 246func (module *prebuiltCompatConfigModule) BaseModuleName() string { 247 return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name()) 248} 249 250var _ platformCompatConfigMetadataProvider = (*prebuiltCompatConfigModule)(nil) 251 252func (module *prebuiltCompatConfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 253 module.metadataFile = module.prebuilt.SingleSourcePath(ctx) 254 255 android.SetProvider(ctx, PlatformCompatConfigMetadataInfoProvider, PlatformCompatConfigMetadataInfo{ 256 CompatConfigMetadata: module.compatConfigMetadata(), 257 IncludeInMergedXml: module.includeInMergedXml(), 258 }) 259} 260 261// A prebuilt version of platform_compat_config that provides the metadata. 262func prebuiltCompatConfigFactory() android.Module { 263 m := &prebuiltCompatConfigModule{} 264 m.AddProperties(&m.properties) 265 android.InitSingleSourcePrebuiltModule(m, &m.properties, "Metadata") 266 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 267 return m 268} 269 270// compat singleton rules 271type platformCompatConfigSingleton struct { 272 metadata android.Path 273} 274 275func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) { 276 277 var compatConfigMetadata android.Paths 278 279 ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { 280 if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled { 281 return 282 } 283 if c, ok := android.OtherModuleProvider(ctx, module, PlatformCompatConfigMetadataInfoProvider); ok { 284 if !android.IsModulePreferredProxy(ctx, module) { 285 return 286 } 287 if !c.IncludeInMergedXml { 288 return 289 } 290 metadata := c.CompatConfigMetadata 291 compatConfigMetadata = append(compatConfigMetadata, metadata) 292 } 293 }) 294 295 if compatConfigMetadata == nil { 296 // nothing to do. 297 return 298 } 299 300 rule := android.NewRuleBuilder(pctx, ctx) 301 outputPath := platformCompatConfigPath(ctx) 302 303 rule.Command(). 304 BuiltTool("process-compat-config"). 305 FlagForEachInput("--xml ", compatConfigMetadata). 306 FlagWithOutput("--merged-config ", outputPath) 307 308 rule.Build("merged-compat-config", "Merge compat config") 309 310 p.metadata = outputPath 311 ctx.DistForGoal("droidcore", p.metadata) 312} 313 314func platformCompatConfigSingletonFactory() android.Singleton { 315 return &platformCompatConfigSingleton{} 316} 317 318// ============== merged_compat_config ================= 319type globalCompatConfigProperties struct { 320 // name of the file into which the metadata will be copied. 321 Filename *string 322} 323 324type globalCompatConfig struct { 325 android.ModuleBase 326 327 properties globalCompatConfigProperties 328} 329 330func (c *globalCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { 331 filename := String(c.properties.Filename) 332 333 inputPath := platformCompatConfigPath(ctx) 334 outputFilePath := android.PathForModuleOut(ctx, filename).OutputPath 335 336 // This ensures that outputFilePath has the correct name for others to 337 // use, as the source file may have a different name. 338 ctx.Build(pctx, android.BuildParams{ 339 Rule: android.Cp, 340 Output: outputFilePath, 341 Input: inputPath, 342 }) 343 344 ctx.SetOutputFiles(android.Paths{outputFilePath}, "") 345} 346 347// global_compat_config provides access to the merged compat config xml file generated by the build. 348func globalCompatConfigFactory() android.Module { 349 module := &globalCompatConfig{} 350 module.AddProperties(&module.properties) 351 android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon) 352 return module 353} 354