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