1// Copyright 2020 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 17// This file contains the module implementations for runtime_resource_overlay and 18// override_runtime_resource_overlay. 19 20import ( 21 "android/soong/android" 22 23 "github.com/google/blueprint" 24 "github.com/google/blueprint/proptools" 25) 26 27func init() { 28 RegisterRuntimeResourceOverlayBuildComponents(android.InitRegistrationContext) 29} 30 31func RegisterRuntimeResourceOverlayBuildComponents(ctx android.RegistrationContext) { 32 ctx.RegisterModuleType("runtime_resource_overlay", RuntimeResourceOverlayFactory) 33 ctx.RegisterModuleType("autogen_runtime_resource_overlay", AutogenRuntimeResourceOverlayFactory) 34 ctx.RegisterModuleType("override_runtime_resource_overlay", OverrideRuntimeResourceOverlayModuleFactory) 35} 36 37type RuntimeResourceOverlayInfo struct { 38 OutputFile android.Path 39 Certificate Certificate 40 Theme string 41 OverriddenManifestPackageName string 42} 43 44var RuntimeResourceOverlayInfoProvider = blueprint.NewProvider[RuntimeResourceOverlayInfo]() 45 46type RuntimeResourceOverlay struct { 47 android.ModuleBase 48 android.DefaultableModuleBase 49 android.OverridableModuleBase 50 aapt 51 52 properties RuntimeResourceOverlayProperties 53 overridableProperties OverridableRuntimeResourceOverlayProperties 54 55 certificate Certificate 56 57 outputFile android.Path 58 installDir android.InstallPath 59} 60 61type RuntimeResourceOverlayProperties struct { 62 // the name of a certificate in the default certificate directory or an android_app_certificate 63 // module name in the form ":module". 64 Certificate proptools.Configurable[string] `android:"replace_instead_of_append"` 65 66 // Name of the signing certificate lineage file. 67 Lineage *string 68 69 // For overriding the --rotation-min-sdk-version property of apksig 70 RotationMinSdkVersion *string 71 72 // optional theme name. If specified, the overlay package will be applied 73 // only when the ro.boot.vendor.overlay.theme system property is set to the same value. 74 Theme *string 75 76 // If not blank, set to the version of the sdk to compile against. This 77 // can be either an API version (e.g. "29" for API level 29 AKA Android 10) 78 // or special subsets of the current platform, for example "none", "current", 79 // "core", "system", "test". See build/soong/java/sdk.go for the full and 80 // up-to-date list of possible values. 81 // Defaults to compiling against the current platform. 82 Sdk_version *string 83 84 // if not blank, set the minimum version of the sdk that the compiled artifacts will run against. 85 // Defaults to sdk_version if not set. 86 Min_sdk_version *string 87 88 // list of android_library modules whose resources are extracted and linked against statically 89 Static_libs proptools.Configurable[[]string] 90 91 // list of android_app modules whose resources are extracted and linked against 92 Resource_libs []string 93 94 // Names of modules to be overridden. Listed modules can only be other overlays 95 // (in Make or Soong). 96 // This does not completely prevent installation of the overridden overlays, but if both 97 // overlays would be installed by default (in PRODUCT_PACKAGES) the other overlay will be removed 98 // from PRODUCT_PACKAGES. 99 Overrides []string 100} 101 102// RRO's partition logic is different from the partition logic of other modules defined in soong/android/paths.go 103// The default partition for RRO is "/product" and not "/system" 104func rroPartition(ctx android.ModuleContext) string { 105 var partition string 106 if ctx.DeviceSpecific() { 107 partition = ctx.DeviceConfig().OdmPath() 108 } else if ctx.SocSpecific() { 109 partition = ctx.DeviceConfig().VendorPath() 110 } else if ctx.SystemExtSpecific() { 111 partition = ctx.DeviceConfig().SystemExtPath() 112 } else { 113 partition = ctx.DeviceConfig().ProductPath() 114 } 115 return partition 116} 117 118func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) { 119 sdkDep := decodeSdkDep(ctx, android.SdkContext(r)) 120 if sdkDep.hasFrameworkLibs() { 121 r.aapt.deps(ctx, sdkDep) 122 } 123 124 cert := android.SrcIsModule(r.properties.Certificate.GetOrDefault(ctx, "")) 125 if cert != "" { 126 ctx.AddDependency(ctx.Module(), certificateTag, cert) 127 } 128 129 ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs.GetOrDefault(ctx, nil)...) 130 ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...) 131 132 for _, aconfig_declaration := range r.aaptProperties.Flags_packages { 133 ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration) 134 } 135} 136 137func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) { 138 // Compile and link resources 139 r.aapt.hasNoCode = true 140 // Do not remove resources without default values nor dedupe resource configurations with the same value 141 aaptLinkFlags := []string{"--no-resource-deduping", "--no-resource-removal"} 142 143 // Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided. 144 hasProduct := android.PrefixInList(r.aaptProperties.Aaptflags, "--product") 145 if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 { 146 aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics()) 147 } 148 149 if !Bool(r.aaptProperties.Aapt_include_all_resources) { 150 // Product AAPT config 151 for _, aaptConfig := range ctx.Config().ProductAAPTConfig() { 152 aaptLinkFlags = append(aaptLinkFlags, "-c", aaptConfig) 153 } 154 155 // Product AAPT preferred config 156 if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 { 157 aaptLinkFlags = append(aaptLinkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig()) 158 } 159 } 160 161 // Allow the override of "package name" and "overlay target package name" 162 manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName()) 163 if overridden || r.overridableProperties.Package_name != nil { 164 // The product override variable has a priority over the package_name property. 165 if !overridden { 166 manifestPackageName = *r.overridableProperties.Package_name 167 } 168 aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, false)...) 169 } 170 if r.overridableProperties.Target_package_name != nil { 171 aaptLinkFlags = append(aaptLinkFlags, 172 "--rename-overlay-target-package "+*r.overridableProperties.Target_package_name) 173 } 174 if r.overridableProperties.Category != nil { 175 aaptLinkFlags = append(aaptLinkFlags, 176 "--rename-overlay-category "+*r.overridableProperties.Category) 177 } 178 aconfigTextFilePaths := getAconfigFilePaths(ctx) 179 r.aapt.buildActions(ctx, 180 aaptBuildActionOptions{ 181 sdkContext: r, 182 enforceDefaultTargetSdkVersion: false, 183 extraLinkFlags: aaptLinkFlags, 184 aconfigTextFiles: aconfigTextFilePaths, 185 }, 186 ) 187 188 // Sign the built package 189 _, _, certificates := collectAppDeps(ctx, r, false, false) 190 r.certificate, certificates = processMainCert(r.ModuleBase, r.properties.Certificate.GetOrDefault(ctx, ""), certificates, ctx) 191 signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk") 192 var lineageFile android.Path 193 if lineage := String(r.properties.Lineage); lineage != "" { 194 lineageFile = android.PathForModuleSrc(ctx, lineage) 195 } 196 197 rotationMinSdkVersion := String(r.properties.RotationMinSdkVersion) 198 199 SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile, rotationMinSdkVersion) 200 201 r.outputFile = signed 202 partition := rroPartition(ctx) 203 r.installDir = android.PathForModuleInPartitionInstall(ctx, partition, "overlay", String(r.properties.Theme)) 204 ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile) 205 206 android.SetProvider(ctx, FlagsPackagesProvider, FlagsPackages{ 207 AconfigTextFiles: aconfigTextFilePaths, 208 }) 209 210 android.SetProvider(ctx, RuntimeResourceOverlayInfoProvider, RuntimeResourceOverlayInfo{ 211 OutputFile: r.outputFile, 212 Certificate: r.Certificate(), 213 Theme: r.Theme(), 214 }) 215 216 ctx.SetOutputFiles([]android.Path{r.outputFile}, "") 217 218 buildComplianceMetadata(ctx) 219} 220 221func (r *RuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { 222 return android.SdkSpecFrom(ctx, String(r.properties.Sdk_version)) 223} 224 225func (r *RuntimeResourceOverlay) SystemModules() string { 226 return "" 227} 228 229func (r *RuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 230 if r.properties.Min_sdk_version != nil { 231 return android.ApiLevelFrom(ctx, *r.properties.Min_sdk_version) 232 } 233 return r.SdkVersion(ctx).ApiLevel 234} 235 236func (r *RuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel { 237 return android.SdkSpecPrivate.ApiLevel 238} 239 240func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 241 return r.SdkVersion(ctx).ApiLevel 242} 243 244func (r *RuntimeResourceOverlay) Certificate() Certificate { 245 return r.certificate 246} 247 248func (r *RuntimeResourceOverlay) Theme() string { 249 return String(r.properties.Theme) 250} 251 252// runtime_resource_overlay generates a resource-only apk file that can overlay application and 253// system resources at run time. 254func RuntimeResourceOverlayFactory() android.Module { 255 module := &RuntimeResourceOverlay{} 256 module.AddProperties( 257 &module.properties, 258 &module.aaptProperties, 259 &module.overridableProperties) 260 261 android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) 262 android.InitDefaultableModule(module) 263 android.InitOverridableModule(module, &module.properties.Overrides) 264 return module 265} 266 267// runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay 268type OverridableRuntimeResourceOverlayProperties struct { 269 // the package name of this app. The package name in the manifest file is used if one was not given. 270 Package_name *string 271 272 // the target package name of this overlay app. The target package name in the manifest file is used if one was not given. 273 Target_package_name *string 274 275 // the rro category of this overlay. The category in the manifest file is used if one was not given. 276 Category *string 277} 278 279type OverrideRuntimeResourceOverlay struct { 280 android.ModuleBase 281 android.OverrideModuleBase 282} 283 284func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(_ android.ModuleContext) { 285 // All the overrides happen in the base module. 286 // TODO(jungjw): Check the base module type. 287} 288 289// override_runtime_resource_overlay is used to create a module based on another 290// runtime_resource_overlay module by overriding some of its properties. 291func OverrideRuntimeResourceOverlayModuleFactory() android.Module { 292 m := &OverrideRuntimeResourceOverlay{} 293 m.AddProperties(&OverridableRuntimeResourceOverlayProperties{}) 294 295 android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon) 296 android.InitOverrideModule(m) 297 return m 298} 299 300var ( 301 generateOverlayManifestFile = pctx.AndroidStaticRule("generate_overlay_manifest", 302 blueprint.RuleParams{ 303 Command: "build/make/tools/generate-enforce-rro-android-manifest.py " + 304 "--package-info $in " + 305 "--partition ${partition} " + 306 "--priority ${priority} -o $out", 307 CommandDeps: []string{"build/make/tools/generate-enforce-rro-android-manifest.py"}, 308 }, "partition", "priority", 309 ) 310) 311 312type AutogenRuntimeResourceOverlay struct { 313 android.ModuleBase 314 aapt 315 316 properties AutogenRuntimeResourceOverlayProperties 317 318 certificate Certificate 319 outputFile android.Path 320} 321 322type AutogenRuntimeResourceOverlayProperties struct { 323 Base *string 324 Sdk_version *string 325 Manifest *string `android:"path"` 326} 327 328func AutogenRuntimeResourceOverlayFactory() android.Module { 329 m := &AutogenRuntimeResourceOverlay{} 330 m.AddProperties(&m.properties) 331 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 332 333 return m 334} 335 336type rroDependencyTag struct { 337 blueprint.DependencyTag 338} 339 340// Autogenerated RROs should always depend on the source android_app that created it. 341func (tag rroDependencyTag) ReplaceSourceWithPrebuilt() bool { 342 return false 343} 344 345var rroDepTag = rroDependencyTag{} 346 347func (a *AutogenRuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) { 348 sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) 349 if sdkDep.hasFrameworkLibs() { 350 a.aapt.deps(ctx, sdkDep) 351 } 352 ctx.AddDependency(ctx.Module(), rroDepTag, proptools.String(a.properties.Base)) 353} 354 355func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) { 356 if !a.Enabled(ctx) { 357 return 358 } 359 var rroDirs android.Paths 360 // Get rro dirs of the base app 361 ctx.VisitDirectDepsWithTag(rroDepTag, func(m android.Module) { 362 aarDep, _ := m.(AndroidLibraryDependency) 363 if ctx.InstallInProduct() { 364 rroDirs = filterRRO(aarDep.RRODirsDepSet(), product) 365 } else { 366 rroDirs = filterRRO(aarDep.RRODirsDepSet(), device) 367 } 368 }) 369 370 if len(rroDirs) == 0 { 371 return 372 } 373 374 // Generate a manifest file 375 genManifest := android.PathForModuleGen(ctx, "AndroidManifest.xml") 376 partition := "vendor" 377 priority := "0" 378 if ctx.InstallInProduct() { 379 partition = "product" 380 priority = "1" 381 } 382 ctx.Build(pctx, android.BuildParams{ 383 Rule: generateOverlayManifestFile, 384 Input: android.PathForModuleSrc(ctx, proptools.String(a.properties.Manifest)), 385 Output: genManifest, 386 Args: map[string]string{ 387 "partition": partition, 388 "priority": priority, 389 }, 390 }) 391 392 // Compile and link resources into package-res.apk 393 a.aapt.hasNoCode = true 394 aaptLinkFlags := []string{"--auto-add-overlay", "--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"} 395 396 a.aapt.buildActions(ctx, 397 aaptBuildActionOptions{ 398 sdkContext: a, 399 extraLinkFlags: aaptLinkFlags, 400 rroDirs: &rroDirs, 401 manifestForAapt: genManifest, 402 aconfigTextFiles: getAconfigFilePaths(ctx), 403 }, 404 ) 405 406 if a.exportPackage == nil { 407 return 408 } 409 // Sign the built package 410 var certificates []Certificate 411 a.certificate, certificates = processMainCert(a.ModuleBase, "", nil, ctx) 412 signed := android.PathForModuleOut(ctx, "signed", a.Name()+".apk") 413 SignAppPackage(ctx, signed, a.exportPackage, certificates, nil, nil, "") 414 a.outputFile = signed 415 416 // Install the signed apk 417 installDir := android.PathForModuleInstall(ctx, "overlay") 418 ctx.InstallFile(installDir, signed.Base(), signed) 419 420 android.SetProvider(ctx, RuntimeResourceOverlayInfoProvider, RuntimeResourceOverlayInfo{ 421 OutputFile: signed, 422 Certificate: a.certificate, 423 }) 424} 425 426func (a *AutogenRuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { 427 return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version)) 428} 429 430func (a *AutogenRuntimeResourceOverlay) SystemModules() string { 431 return "" 432} 433 434func (a *AutogenRuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 435 return a.SdkVersion(ctx).ApiLevel 436} 437 438func (r *AutogenRuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel { 439 return android.SdkSpecPrivate.ApiLevel 440} 441 442func (a *AutogenRuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { 443 return a.SdkVersion(ctx).ApiLevel 444} 445 446func (a *AutogenRuntimeResourceOverlay) InstallInProduct() bool { 447 return a.ProductSpecific() 448} 449