1// Copyright 2015 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 android 16 17import ( 18 "fmt" 19 "reflect" 20 "runtime" 21 "strings" 22 23 "github.com/google/blueprint/proptools" 24) 25 26func init() { 27 PreDepsMutators(func(ctx RegisterMutatorsContext) { 28 ctx.BottomUp("variable", VariableMutator).Parallel() 29 }) 30} 31 32type variableProperties struct { 33 Product_variables struct { 34 Platform_sdk_version struct { 35 Asflags []string 36 Cflags []string 37 } 38 39 // unbundled_build is a catch-all property to annotate modules that don't build in one or 40 // more unbundled branches, usually due to dependencies missing from the manifest. 41 Unbundled_build struct { 42 Enabled *bool `android:"arch_variant"` 43 } `android:"arch_variant"` 44 45 Malloc_not_svelte struct { 46 Cflags []string `android:"arch_variant"` 47 Shared_libs []string `android:"arch_variant"` 48 Whole_static_libs []string `android:"arch_variant"` 49 Exclude_static_libs []string `android:"arch_variant"` 50 } `android:"arch_variant"` 51 52 Malloc_zero_contents struct { 53 Cflags []string `android:"arch_variant"` 54 } `android:"arch_variant"` 55 56 Malloc_pattern_fill_contents struct { 57 Cflags []string `android:"arch_variant"` 58 } `android:"arch_variant"` 59 60 Safestack struct { 61 Cflags []string `android:"arch_variant"` 62 } `android:"arch_variant"` 63 64 Binder32bit struct { 65 Cflags []string 66 } 67 68 Override_rs_driver struct { 69 Cflags []string 70 } 71 72 // treble_linker_namespaces is true when the system/vendor linker namespace separation is 73 // enabled. 74 Treble_linker_namespaces struct { 75 Cflags []string 76 } 77 // enforce_vintf_manifest is true when a device is required to have a vintf manifest. 78 Enforce_vintf_manifest struct { 79 Cflags []string 80 } 81 82 // debuggable is true for eng and userdebug builds, and can be used to turn on additional 83 // debugging features that don't significantly impact runtime behavior. userdebug builds 84 // are used for dogfooding and performance testing, and should be as similar to user builds 85 // as possible. 86 Debuggable struct { 87 Cflags []string 88 Cppflags []string 89 Init_rc []string 90 Required []string 91 Host_required []string 92 Target_required []string 93 } 94 95 // eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging 96 // features. 97 Eng struct { 98 Cflags []string 99 Cppflags []string 100 Lto struct { 101 Never *bool 102 } 103 Sanitize struct { 104 Address *bool 105 } 106 Optimize struct { 107 Enabled *bool 108 } 109 } 110 111 Pdk struct { 112 Enabled *bool `android:"arch_variant"` 113 } `android:"arch_variant"` 114 115 Uml struct { 116 Cppflags []string 117 } 118 119 Use_lmkd_stats_log struct { 120 Cflags []string 121 } 122 123 Arc struct { 124 Cflags []string 125 Exclude_srcs []string 126 Include_dirs []string 127 Shared_libs []string 128 Static_libs []string 129 Srcs []string 130 } 131 132 Flatten_apex struct { 133 Enabled *bool 134 } 135 136 Experimental_mte struct { 137 Cflags []string `android:"arch_variant"` 138 } `android:"arch_variant"` 139 140 Native_coverage struct { 141 Src *string `android:"arch_variant"` 142 Srcs []string `android:"arch_variant"` 143 Exclude_srcs []string `android:"arch_variant"` 144 } `android:"arch_variant"` 145 } `android:"arch_variant"` 146} 147 148var defaultProductVariables interface{} = variableProperties{} 149 150type productVariables struct { 151 // Suffix to add to generated Makefiles 152 Make_suffix *string `json:",omitempty"` 153 154 BuildId *string `json:",omitempty"` 155 BuildNumberFile *string `json:",omitempty"` 156 157 Platform_version_name *string `json:",omitempty"` 158 Platform_sdk_version *int `json:",omitempty"` 159 Platform_sdk_codename *string `json:",omitempty"` 160 Platform_sdk_final *bool `json:",omitempty"` 161 Platform_version_active_codenames []string `json:",omitempty"` 162 Platform_vndk_version *string `json:",omitempty"` 163 Platform_systemsdk_versions []string `json:",omitempty"` 164 Platform_security_patch *string `json:",omitempty"` 165 Platform_preview_sdk_version *string `json:",omitempty"` 166 Platform_min_supported_target_sdk_version *string `json:",omitempty"` 167 Platform_base_os *string `json:",omitempty"` 168 169 DeviceName *string `json:",omitempty"` 170 DeviceArch *string `json:",omitempty"` 171 DeviceArchVariant *string `json:",omitempty"` 172 DeviceCpuVariant *string `json:",omitempty"` 173 DeviceAbi []string `json:",omitempty"` 174 DeviceVndkVersion *string `json:",omitempty"` 175 DeviceSystemSdkVersions []string `json:",omitempty"` 176 177 DeviceSecondaryArch *string `json:",omitempty"` 178 DeviceSecondaryArchVariant *string `json:",omitempty"` 179 DeviceSecondaryCpuVariant *string `json:",omitempty"` 180 DeviceSecondaryAbi []string `json:",omitempty"` 181 182 NativeBridgeArch *string `json:",omitempty"` 183 NativeBridgeArchVariant *string `json:",omitempty"` 184 NativeBridgeCpuVariant *string `json:",omitempty"` 185 NativeBridgeAbi []string `json:",omitempty"` 186 NativeBridgeRelativePath *string `json:",omitempty"` 187 188 NativeBridgeSecondaryArch *string `json:",omitempty"` 189 NativeBridgeSecondaryArchVariant *string `json:",omitempty"` 190 NativeBridgeSecondaryCpuVariant *string `json:",omitempty"` 191 NativeBridgeSecondaryAbi []string `json:",omitempty"` 192 NativeBridgeSecondaryRelativePath *string `json:",omitempty"` 193 194 HostArch *string `json:",omitempty"` 195 HostSecondaryArch *string `json:",omitempty"` 196 197 CrossHost *string `json:",omitempty"` 198 CrossHostArch *string `json:",omitempty"` 199 CrossHostSecondaryArch *string `json:",omitempty"` 200 201 DeviceResourceOverlays []string `json:",omitempty"` 202 ProductResourceOverlays []string `json:",omitempty"` 203 EnforceRROTargets []string `json:",omitempty"` 204 // TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency. 205 EnforceRROExemptedTargets []string `json:",omitempty"` 206 EnforceRROExcludedOverlays []string `json:",omitempty"` 207 208 AAPTCharacteristics *string `json:",omitempty"` 209 AAPTConfig []string `json:",omitempty"` 210 AAPTPreferredConfig *string `json:",omitempty"` 211 AAPTPrebuiltDPI []string `json:",omitempty"` 212 213 DefaultAppCertificate *string `json:",omitempty"` 214 215 AppsDefaultVersionName *string `json:",omitempty"` 216 217 Allow_missing_dependencies *bool `json:",omitempty"` 218 Unbundled_build *bool `json:",omitempty"` 219 Unbundled_build_apps *bool `json:",omitempty"` 220 Unbundled_build_sdks_from_source *bool `json:",omitempty"` 221 Malloc_not_svelte *bool `json:",omitempty"` 222 Malloc_zero_contents *bool `json:",omitempty"` 223 Malloc_pattern_fill_contents *bool `json:",omitempty"` 224 Safestack *bool `json:",omitempty"` 225 HostStaticBinaries *bool `json:",omitempty"` 226 Binder32bit *bool `json:",omitempty"` 227 UseGoma *bool `json:",omitempty"` 228 UseRBE *bool `json:",omitempty"` 229 UseRBEJAVAC *bool `json:",omitempty"` 230 UseRBER8 *bool `json:",omitempty"` 231 UseRBED8 *bool `json:",omitempty"` 232 Debuggable *bool `json:",omitempty"` 233 Eng *bool `json:",omitempty"` 234 Treble_linker_namespaces *bool `json:",omitempty"` 235 Enforce_vintf_manifest *bool `json:",omitempty"` 236 Pdk *bool `json:",omitempty"` 237 Uml *bool `json:",omitempty"` 238 Use_lmkd_stats_log *bool `json:",omitempty"` 239 Arc *bool `json:",omitempty"` 240 MinimizeJavaDebugInfo *bool `json:",omitempty"` 241 242 Check_elf_files *bool `json:",omitempty"` 243 244 UncompressPrivAppDex *bool `json:",omitempty"` 245 ModulesLoadedByPrivilegedModules []string `json:",omitempty"` 246 247 BootJars []string `json:",omitempty"` 248 UpdatableBootJars []string `json:",omitempty"` 249 250 IntegerOverflowExcludePaths []string `json:",omitempty"` 251 252 EnableCFI *bool `json:",omitempty"` 253 CFIExcludePaths []string `json:",omitempty"` 254 CFIIncludePaths []string `json:",omitempty"` 255 256 DisableScudo *bool `json:",omitempty"` 257 258 Experimental_mte *bool `json:",omitempty"` 259 260 VendorPath *string `json:",omitempty"` 261 OdmPath *string `json:",omitempty"` 262 ProductPath *string `json:",omitempty"` 263 SystemExtPath *string `json:",omitempty"` 264 265 ClangTidy *bool `json:",omitempty"` 266 TidyChecks *string `json:",omitempty"` 267 268 SamplingPGO *bool `json:",omitempty"` 269 270 JavaCoveragePaths []string `json:",omitempty"` 271 JavaCoverageExcludePaths []string `json:",omitempty"` 272 273 GcovCoverage *bool `json:",omitempty"` 274 ClangCoverage *bool `json:",omitempty"` 275 NativeCoveragePaths []string `json:",omitempty"` 276 NativeCoverageExcludePaths []string `json:",omitempty"` 277 278 // Set by NewConfig 279 Native_coverage *bool 280 281 SanitizeHost []string `json:",omitempty"` 282 SanitizeDevice []string `json:",omitempty"` 283 SanitizeDeviceDiag []string `json:",omitempty"` 284 SanitizeDeviceArch []string `json:",omitempty"` 285 286 ArtUseReadBarrier *bool `json:",omitempty"` 287 288 BtConfigIncludeDir *string `json:",omitempty"` 289 290 Override_rs_driver *string `json:",omitempty"` 291 292 Fuchsia *bool `json:",omitempty"` 293 294 DeviceKernelHeaders []string `json:",omitempty"` 295 296 ExtraVndkVersions []string `json:",omitempty"` 297 298 NamespacesToExport []string `json:",omitempty"` 299 300 PgoAdditionalProfileDirs []string `json:",omitempty"` 301 302 VndkUseCoreVariant *bool `json:",omitempty"` 303 VndkSnapshotBuildArtifacts *bool `json:",omitempty"` 304 305 BoardVendorSepolicyDirs []string `json:",omitempty"` 306 BoardOdmSepolicyDirs []string `json:",omitempty"` 307 BoardPlatPublicSepolicyDirs []string `json:",omitempty"` 308 BoardPlatPrivateSepolicyDirs []string `json:",omitempty"` 309 BoardSepolicyM4Defs []string `json:",omitempty"` 310 311 VendorVars map[string]map[string]string `json:",omitempty"` 312 313 Ndk_abis *bool `json:",omitempty"` 314 Exclude_draft_ndk_apis *bool `json:",omitempty"` 315 316 Flatten_apex *bool `json:",omitempty"` 317 Aml_abis *bool `json:",omitempty"` 318 319 DexpreoptGlobalConfig *string `json:",omitempty"` 320 321 ManifestPackageNameOverrides []string `json:",omitempty"` 322 CertificateOverrides []string `json:",omitempty"` 323 PackageNameOverrides []string `json:",omitempty"` 324 325 EnforceSystemCertificate *bool `json:",omitempty"` 326 EnforceSystemCertificateAllowList []string `json:",omitempty"` 327 328 ProductHiddenAPIStubs []string `json:",omitempty"` 329 ProductHiddenAPIStubsSystem []string `json:",omitempty"` 330 ProductHiddenAPIStubsTest []string `json:",omitempty"` 331 332 ProductPublicSepolicyDirs []string `json:",omitempty"` 333 ProductPrivateSepolicyDirs []string `json:",omitempty"` 334 ProductCompatibleProperty *bool `json:",omitempty"` 335 336 ProductVndkVersion *string `json:",omitempty"` 337 338 TargetFSConfigGen []string `json:",omitempty"` 339 340 MissingUsesLibraries []string `json:",omitempty"` 341 342 EnforceProductPartitionInterface *bool `json:",omitempty"` 343 344 InstallExtraFlattenedApexes *bool `json:",omitempty"` 345 346 BoardUsesRecoveryAsBoot *bool `json:",omitempty"` 347 348 BoardKernelBinaries []string `json:",omitempty"` 349} 350 351func boolPtr(v bool) *bool { 352 return &v 353} 354 355func intPtr(v int) *int { 356 return &v 357} 358 359func stringPtr(v string) *string { 360 return &v 361} 362 363func (v *productVariables) SetDefaultConfig() { 364 *v = productVariables{ 365 BuildNumberFile: stringPtr("build_number.txt"), 366 367 Platform_version_name: stringPtr("Q"), 368 Platform_sdk_version: intPtr(28), 369 Platform_sdk_codename: stringPtr("Q"), 370 Platform_sdk_final: boolPtr(false), 371 Platform_version_active_codenames: []string{"Q"}, 372 Platform_vndk_version: stringPtr("Q"), 373 374 HostArch: stringPtr("x86_64"), 375 HostSecondaryArch: stringPtr("x86"), 376 DeviceName: stringPtr("generic_arm64"), 377 DeviceArch: stringPtr("arm64"), 378 DeviceArchVariant: stringPtr("armv8-a"), 379 DeviceCpuVariant: stringPtr("generic"), 380 DeviceAbi: []string{"arm64-v8a"}, 381 DeviceSecondaryArch: stringPtr("arm"), 382 DeviceSecondaryArchVariant: stringPtr("armv8-a"), 383 DeviceSecondaryCpuVariant: stringPtr("generic"), 384 DeviceSecondaryAbi: []string{"armeabi-v7a", "armeabi"}, 385 386 AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}, 387 AAPTPreferredConfig: stringPtr("xhdpi"), 388 AAPTCharacteristics: stringPtr("nosdcard"), 389 AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"}, 390 391 Malloc_not_svelte: boolPtr(true), 392 Malloc_zero_contents: boolPtr(false), 393 Malloc_pattern_fill_contents: boolPtr(false), 394 Safestack: boolPtr(false), 395 } 396 397 if runtime.GOOS == "linux" { 398 v.CrossHost = stringPtr("windows") 399 v.CrossHostArch = stringPtr("x86") 400 v.CrossHostSecondaryArch = stringPtr("x86_64") 401 } 402} 403 404func VariableMutator(mctx BottomUpMutatorContext) { 405 var module Module 406 var ok bool 407 if module, ok = mctx.Module().(Module); !ok { 408 return 409 } 410 411 // TODO: depend on config variable, create variants, propagate variants up tree 412 a := module.base() 413 414 if a.variableProperties == nil { 415 return 416 } 417 418 variableValues := reflect.ValueOf(a.variableProperties).Elem().FieldByName("Product_variables") 419 420 for i := 0; i < variableValues.NumField(); i++ { 421 variableValue := variableValues.Field(i) 422 name := variableValues.Type().Field(i).Name 423 property := "product_variables." + proptools.PropertyNameForField(name) 424 425 // Check that the variable was set for the product 426 val := reflect.ValueOf(mctx.Config().productVariables).FieldByName(name) 427 if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() { 428 continue 429 } 430 431 val = val.Elem() 432 433 // For bools, check that the value is true 434 if val.Kind() == reflect.Bool && val.Bool() == false { 435 continue 436 } 437 438 // Check if any properties were set for the module 439 if variableValue.IsZero() { 440 continue 441 } 442 a.setVariableProperties(mctx, property, variableValue, val.Interface()) 443 } 444} 445 446func (m *ModuleBase) setVariableProperties(ctx BottomUpMutatorContext, 447 prefix string, productVariablePropertyValue reflect.Value, variableValue interface{}) { 448 449 printfIntoProperties(ctx, prefix, productVariablePropertyValue, variableValue) 450 451 err := proptools.AppendMatchingProperties(m.generalProperties, 452 productVariablePropertyValue.Addr().Interface(), nil) 453 if err != nil { 454 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 455 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 456 } else { 457 panic(err) 458 } 459 } 460} 461 462func printfIntoPropertiesError(ctx BottomUpMutatorContext, prefix string, 463 productVariablePropertyValue reflect.Value, i int, err error) { 464 465 field := productVariablePropertyValue.Type().Field(i).Name 466 property := prefix + "." + proptools.PropertyNameForField(field) 467 ctx.PropertyErrorf(property, "%s", err) 468} 469 470func printfIntoProperties(ctx BottomUpMutatorContext, prefix string, 471 productVariablePropertyValue reflect.Value, variableValue interface{}) { 472 473 for i := 0; i < productVariablePropertyValue.NumField(); i++ { 474 propertyValue := productVariablePropertyValue.Field(i) 475 kind := propertyValue.Kind() 476 if kind == reflect.Ptr { 477 if propertyValue.IsNil() { 478 continue 479 } 480 propertyValue = propertyValue.Elem() 481 } 482 switch propertyValue.Kind() { 483 case reflect.String: 484 err := printfIntoProperty(propertyValue, variableValue) 485 if err != nil { 486 printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err) 487 } 488 case reflect.Slice: 489 for j := 0; j < propertyValue.Len(); j++ { 490 err := printfIntoProperty(propertyValue.Index(j), variableValue) 491 if err != nil { 492 printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err) 493 } 494 } 495 case reflect.Bool: 496 // Nothing 497 case reflect.Struct: 498 printfIntoProperties(ctx, prefix, propertyValue, variableValue) 499 default: 500 panic(fmt.Errorf("unsupported field kind %q", propertyValue.Kind())) 501 } 502 } 503} 504 505func printfIntoProperty(propertyValue reflect.Value, variableValue interface{}) error { 506 s := propertyValue.String() 507 508 count := strings.Count(s, "%") 509 if count == 0 { 510 return nil 511 } 512 513 if count > 1 { 514 return fmt.Errorf("product variable properties only support a single '%%'") 515 } 516 517 if strings.Contains(s, "%d") { 518 switch v := variableValue.(type) { 519 case int: 520 // Nothing 521 case bool: 522 if v { 523 variableValue = 1 524 } else { 525 variableValue = 0 526 } 527 default: 528 return fmt.Errorf("unsupported type %T for %%d", variableValue) 529 } 530 } else if strings.Contains(s, "%s") { 531 switch variableValue.(type) { 532 case string: 533 // Nothing 534 default: 535 return fmt.Errorf("unsupported type %T for %%s", variableValue) 536 } 537 } else { 538 return fmt.Errorf("unsupported %% in product variable property") 539 } 540 541 propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, variableValue))) 542 543 return nil 544} 545 546var variablePropTypeMap OncePer 547 548// sliceToTypeArray takes a slice of property structs and returns a reflection created array containing the 549// reflect.Types of each property struct. The result can be used as a key in a map. 550func sliceToTypeArray(s []interface{}) interface{} { 551 // Create an array using reflection whose length is the length of the input slice 552 ret := reflect.New(reflect.ArrayOf(len(s), reflect.TypeOf(reflect.TypeOf(0)))).Elem() 553 for i, e := range s { 554 ret.Index(i).Set(reflect.ValueOf(reflect.TypeOf(e))) 555 } 556 return ret.Interface() 557} 558 559func initProductVariableModule(m Module) { 560 base := m.base() 561 562 // Allow tests to override the default product variables 563 if base.variableProperties == nil { 564 base.variableProperties = defaultProductVariables 565 } 566 // Filter the product variables properties to the ones that exist on this module 567 base.variableProperties = createVariableProperties(m.GetProperties(), base.variableProperties) 568 if base.variableProperties != nil { 569 m.AddProperties(base.variableProperties) 570 } 571} 572 573// createVariableProperties takes the list of property structs for a module and returns a property struct that 574// contains the product variable properties that exist in the property structs, or nil if there are none. It 575// caches the result. 576func createVariableProperties(moduleTypeProps []interface{}, productVariables interface{}) interface{} { 577 // Convert the moduleTypeProps to an array of reflect.Types that can be used as a key in the OncePer. 578 key := sliceToTypeArray(moduleTypeProps) 579 580 // Use the variablePropTypeMap OncePer to cache the result for each set of property struct types. 581 typ, _ := variablePropTypeMap.Once(NewCustomOnceKey(key), func() interface{} { 582 // Compute the filtered property struct type. 583 return createVariablePropertiesType(moduleTypeProps, productVariables) 584 }).(reflect.Type) 585 586 if typ == nil { 587 return nil 588 } 589 590 // Create a new pointer to a filtered property struct. 591 return reflect.New(typ).Interface() 592} 593 594// createVariablePropertiesType creates a new type that contains only the product variable properties that exist in 595// a list of property structs. 596func createVariablePropertiesType(moduleTypeProps []interface{}, productVariables interface{}) reflect.Type { 597 typ, _ := proptools.FilterPropertyStruct(reflect.TypeOf(productVariables), 598 func(field reflect.StructField, prefix string) (bool, reflect.StructField) { 599 // Filter function, returns true if the field should be in the resulting struct 600 if prefix == "" { 601 // Keep the top level Product_variables field 602 return true, field 603 } 604 _, rest := splitPrefix(prefix) 605 if rest == "" { 606 // Keep the 2nd level field (i.e. Product_variables.Eng) 607 return true, field 608 } 609 610 // Strip off the first 2 levels of the prefix 611 _, prefix = splitPrefix(rest) 612 613 for _, p := range moduleTypeProps { 614 if fieldExistsByNameRecursive(reflect.TypeOf(p).Elem(), prefix, field.Name) { 615 // Keep any fields that exist in one of the property structs 616 return true, field 617 } 618 } 619 620 return false, field 621 }) 622 return typ 623} 624 625func splitPrefix(prefix string) (first, rest string) { 626 index := strings.IndexByte(prefix, '.') 627 if index == -1 { 628 return prefix, "" 629 } 630 return prefix[:index], prefix[index+1:] 631} 632 633func fieldExistsByNameRecursive(t reflect.Type, prefix, name string) bool { 634 if t.Kind() != reflect.Struct { 635 panic(fmt.Errorf("fieldExistsByNameRecursive can only be called on a reflect.Struct")) 636 } 637 638 if prefix != "" { 639 split := strings.SplitN(prefix, ".", 2) 640 firstPrefix := split[0] 641 rest := "" 642 if len(split) > 1 { 643 rest = split[1] 644 } 645 f, exists := t.FieldByName(firstPrefix) 646 if !exists { 647 return false 648 } 649 ft := f.Type 650 if ft.Kind() == reflect.Ptr { 651 ft = ft.Elem() 652 } 653 if ft.Kind() != reflect.Struct { 654 panic(fmt.Errorf("field %q in %q is not a struct", firstPrefix, t)) 655 } 656 return fieldExistsByNameRecursive(ft, rest, name) 657 } else { 658 _, exists := t.FieldByName(name) 659 return exists 660 } 661} 662