1// Copyright (C) 2019 The Android Open Source Project 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 apex 16 17import ( 18 "fmt" 19 "strconv" 20 "strings" 21 22 "android/soong/android" 23 "android/soong/java" 24 25 "github.com/google/blueprint" 26 27 "github.com/google/blueprint/proptools" 28) 29 30var ( 31 extractMatchingApex = pctx.StaticRule( 32 "extractMatchingApex", 33 blueprint.RuleParams{ 34 Command: `rm -rf "$out" && ` + 35 `${extract_apks} -o "${out}" -allow-prereleased=${allow-prereleased} ` + 36 `-sdk-version=${sdk-version} -abis=${abis} -screen-densities=all -extract-single ` + 37 `${in}`, 38 CommandDeps: []string{"${extract_apks}"}, 39 }, 40 "abis", "allow-prereleased", "sdk-version") 41) 42 43type prebuilt interface { 44 isForceDisabled() bool 45 InstallFilename() string 46} 47 48type prebuiltCommon struct { 49 prebuilt android.Prebuilt 50 properties prebuiltCommonProperties 51} 52 53type prebuiltCommonProperties struct { 54 ForceDisable bool `blueprint:"mutated"` 55} 56 57func (p *prebuiltCommon) Prebuilt() *android.Prebuilt { 58 return &p.prebuilt 59} 60 61func (p *prebuiltCommon) isForceDisabled() bool { 62 return p.properties.ForceDisable 63} 64 65func (p *prebuiltCommon) checkForceDisable(ctx android.ModuleContext) bool { 66 // If the device is configured to use flattened APEX, force disable the prebuilt because 67 // the prebuilt is a non-flattened one. 68 forceDisable := ctx.Config().FlattenApex() 69 70 // Force disable the prebuilts when we are doing unbundled build. We do unbundled build 71 // to build the prebuilts themselves. 72 forceDisable = forceDisable || ctx.Config().UnbundledBuild() 73 74 // Force disable the prebuilts when coverage is enabled. 75 forceDisable = forceDisable || ctx.DeviceConfig().NativeCoverageEnabled() 76 forceDisable = forceDisable || ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") 77 78 // b/137216042 don't use prebuilts when address sanitizer is on 79 forceDisable = forceDisable || android.InList("address", ctx.Config().SanitizeDevice()) || 80 android.InList("hwaddress", ctx.Config().SanitizeDevice()) 81 82 if forceDisable && p.prebuilt.SourceExists() { 83 p.properties.ForceDisable = true 84 return true 85 } 86 return false 87} 88 89type Prebuilt struct { 90 android.ModuleBase 91 prebuiltCommon 92 93 properties PrebuiltProperties 94 95 inputApex android.Path 96 installDir android.InstallPath 97 installFilename string 98 outputApex android.WritablePath 99 100 // list of commands to create symlinks for backward compatibility. 101 // these commands will be attached as LOCAL_POST_INSTALL_CMD 102 compatSymlinks []string 103} 104 105type PrebuiltProperties struct { 106 // the path to the prebuilt .apex file to import. 107 Source string `blueprint:"mutated"` 108 109 Src *string 110 Arch struct { 111 Arm struct { 112 Src *string 113 } 114 Arm64 struct { 115 Src *string 116 } 117 X86 struct { 118 Src *string 119 } 120 X86_64 struct { 121 Src *string 122 } 123 } 124 125 Installable *bool 126 // Optional name for the installed apex. If unspecified, name of the 127 // module is used as the file name 128 Filename *string 129 130 // Names of modules to be overridden. Listed modules can only be other binaries 131 // (in Make or Soong). 132 // This does not completely prevent installation of the overridden binaries, but if both 133 // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed 134 // from PRODUCT_PACKAGES. 135 Overrides []string 136} 137 138func (p *Prebuilt) installable() bool { 139 return p.properties.Installable == nil || proptools.Bool(p.properties.Installable) 140} 141 142func (p *Prebuilt) OutputFiles(tag string) (android.Paths, error) { 143 switch tag { 144 case "": 145 return android.Paths{p.outputApex}, nil 146 default: 147 return nil, fmt.Errorf("unsupported module reference tag %q", tag) 148 } 149} 150 151func (p *Prebuilt) InstallFilename() string { 152 return proptools.StringDefault(p.properties.Filename, p.BaseModuleName()+imageApexSuffix) 153} 154 155func (p *Prebuilt) Name() string { 156 return p.prebuiltCommon.prebuilt.Name(p.ModuleBase.Name()) 157} 158 159// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex. 160func PrebuiltFactory() android.Module { 161 module := &Prebuilt{} 162 module.AddProperties(&module.properties) 163 android.InitSingleSourcePrebuiltModule(module, &module.properties, "Source") 164 android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) 165 return module 166} 167 168func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) { 169 // This is called before prebuilt_select and prebuilt_postdeps mutators 170 // The mutators requires that src to be set correctly for each arch so that 171 // arch variants are disabled when src is not provided for the arch. 172 if len(ctx.MultiTargets()) != 1 { 173 ctx.ModuleErrorf("compile_multilib shouldn't be \"both\" for prebuilt_apex") 174 return 175 } 176 var src string 177 switch ctx.MultiTargets()[0].Arch.ArchType { 178 case android.Arm: 179 src = String(p.properties.Arch.Arm.Src) 180 case android.Arm64: 181 src = String(p.properties.Arch.Arm64.Src) 182 case android.X86: 183 src = String(p.properties.Arch.X86.Src) 184 case android.X86_64: 185 src = String(p.properties.Arch.X86_64.Src) 186 default: 187 ctx.ModuleErrorf("prebuilt_apex does not support %q", ctx.MultiTargets()[0].Arch.String()) 188 return 189 } 190 if src == "" { 191 src = String(p.properties.Src) 192 } 193 p.properties.Source = src 194} 195 196func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { 197 // TODO(jungjw): Check the key validity. 198 p.inputApex = p.Prebuilt().SingleSourcePath(ctx) 199 p.installDir = android.PathForModuleInstall(ctx, "apex") 200 p.installFilename = p.InstallFilename() 201 if !strings.HasSuffix(p.installFilename, imageApexSuffix) { 202 ctx.ModuleErrorf("filename should end in %s for prebuilt_apex", imageApexSuffix) 203 } 204 p.outputApex = android.PathForModuleOut(ctx, p.installFilename) 205 ctx.Build(pctx, android.BuildParams{ 206 Rule: android.Cp, 207 Input: p.inputApex, 208 Output: p.outputApex, 209 }) 210 211 if p.prebuiltCommon.checkForceDisable(ctx) { 212 p.SkipInstall() 213 return 214 } 215 216 if p.installable() { 217 ctx.InstallFile(p.installDir, p.installFilename, p.inputApex) 218 } 219 220 // in case that prebuilt_apex replaces source apex (using prefer: prop) 221 p.compatSymlinks = makeCompatSymlinks(p.BaseModuleName(), ctx) 222 // or that prebuilt_apex overrides other apexes (using overrides: prop) 223 for _, overridden := range p.properties.Overrides { 224 p.compatSymlinks = append(p.compatSymlinks, makeCompatSymlinks(overridden, ctx)...) 225 } 226} 227 228func (p *Prebuilt) AndroidMkEntries() []android.AndroidMkEntries { 229 return []android.AndroidMkEntries{android.AndroidMkEntries{ 230 Class: "ETC", 231 OutputFile: android.OptionalPathForPath(p.inputApex), 232 Include: "$(BUILD_PREBUILT)", 233 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 234 func(entries *android.AndroidMkEntries) { 235 entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String()) 236 entries.SetString("LOCAL_MODULE_STEM", p.installFilename) 237 entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable()) 238 entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.properties.Overrides...) 239 if len(p.compatSymlinks) > 0 { 240 entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(p.compatSymlinks, " && ")) 241 } 242 }, 243 }, 244 }} 245} 246 247type ApexSet struct { 248 android.ModuleBase 249 prebuiltCommon 250 251 properties ApexSetProperties 252 253 installDir android.InstallPath 254 installFilename string 255 outputApex android.WritablePath 256 257 // list of commands to create symlinks for backward compatibility. 258 // these commands will be attached as LOCAL_POST_INSTALL_CMD 259 compatSymlinks []string 260} 261 262type ApexSetProperties struct { 263 // the .apks file path that contains prebuilt apex files to be extracted. 264 Set *string 265 266 // whether the extracted apex file installable. 267 Installable *bool 268 269 // optional name for the installed apex. If unspecified, name of the 270 // module is used as the file name 271 Filename *string 272 273 // names of modules to be overridden. Listed modules can only be other binaries 274 // (in Make or Soong). 275 // This does not completely prevent installation of the overridden binaries, but if both 276 // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed 277 // from PRODUCT_PACKAGES. 278 Overrides []string 279 280 // apexes in this set use prerelease SDK version 281 Prerelease *bool 282} 283 284func (a *ApexSet) installable() bool { 285 return a.properties.Installable == nil || proptools.Bool(a.properties.Installable) 286} 287 288func (a *ApexSet) InstallFilename() string { 289 return proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+imageApexSuffix) 290} 291 292func (a *ApexSet) Name() string { 293 return a.prebuiltCommon.prebuilt.Name(a.ModuleBase.Name()) 294} 295 296func (a *ApexSet) Overrides() []string { 297 return a.properties.Overrides 298} 299 300// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex. 301func apexSetFactory() android.Module { 302 module := &ApexSet{} 303 module.AddProperties(&module.properties) 304 android.InitSingleSourcePrebuiltModule(module, &module.properties, "Set") 305 android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) 306 return module 307} 308 309func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { 310 a.installFilename = a.InstallFilename() 311 if !strings.HasSuffix(a.installFilename, imageApexSuffix) { 312 ctx.ModuleErrorf("filename should end in %s for apex_set", imageApexSuffix) 313 } 314 315 apexSet := a.prebuiltCommon.prebuilt.SingleSourcePath(ctx) 316 a.outputApex = android.PathForModuleOut(ctx, a.installFilename) 317 ctx.Build(pctx, 318 android.BuildParams{ 319 Rule: extractMatchingApex, 320 Description: "Extract an apex from an apex set", 321 Inputs: android.Paths{apexSet}, 322 Output: a.outputApex, 323 Args: map[string]string{ 324 "abis": strings.Join(java.SupportedAbis(ctx), ","), 325 "allow-prereleased": strconv.FormatBool(proptools.Bool(a.properties.Prerelease)), 326 "sdk-version": ctx.Config().PlatformSdkVersion(), 327 }, 328 }) 329 330 if a.prebuiltCommon.checkForceDisable(ctx) { 331 a.SkipInstall() 332 return 333 } 334 335 a.installDir = android.PathForModuleInstall(ctx, "apex") 336 if a.installable() { 337 ctx.InstallFile(a.installDir, a.installFilename, a.outputApex) 338 } 339 340 // in case that apex_set replaces source apex (using prefer: prop) 341 a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx) 342 // or that apex_set overrides other apexes (using overrides: prop) 343 for _, overridden := range a.properties.Overrides { 344 a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...) 345 } 346} 347 348func (a *ApexSet) AndroidMkEntries() []android.AndroidMkEntries { 349 return []android.AndroidMkEntries{android.AndroidMkEntries{ 350 Class: "ETC", 351 OutputFile: android.OptionalPathForPath(a.outputApex), 352 Include: "$(BUILD_PREBUILT)", 353 ExtraEntries: []android.AndroidMkExtraEntriesFunc{ 354 func(entries *android.AndroidMkEntries) { 355 entries.SetString("LOCAL_MODULE_PATH", a.installDir.ToMakePath().String()) 356 entries.SetString("LOCAL_MODULE_STEM", a.installFilename) 357 entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !a.installable()) 358 entries.AddStrings("LOCAL_OVERRIDES_MODULES", a.properties.Overrides...) 359 if len(a.compatSymlinks) > 0 { 360 entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(a.compatSymlinks, " && ")) 361 } 362 }, 363 }, 364 }} 365} 366