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