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