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 } `android:"arch_variant"` 49 50 Safestack struct { 51 Cflags []string `android:"arch_variant"` 52 } `android:"arch_variant"` 53 54 Binder32bit struct { 55 Cflags []string 56 } 57 58 Override_rs_driver struct { 59 Cflags []string 60 } 61 62 // Product_is_iot is true for Android Things devices. 63 Product_is_iot struct { 64 Cflags []string 65 Enabled bool 66 Exclude_srcs []string 67 Init_rc []string 68 Shared_libs []string 69 Srcs []string 70 Static_libs []string 71 } 72 73 // treble_linker_namespaces is true when the system/vendor linker namespace separation is 74 // enabled. 75 Treble_linker_namespaces struct { 76 Cflags []string 77 } 78 // enforce_vintf_manifest is true when a device is required to have a vintf manifest. 79 Enforce_vintf_manifest struct { 80 Cflags []string 81 } 82 83 // debuggable is true for eng and userdebug builds, and can be used to turn on additional 84 // debugging features that don't significantly impact runtime behavior. userdebug builds 85 // are used for dogfooding and performance testing, and should be as similar to user builds 86 // as possible. 87 Debuggable struct { 88 Cflags []string 89 Cppflags []string 90 Init_rc []string 91 Required []string 92 } 93 94 // eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging 95 // features. 96 Eng struct { 97 Cflags []string 98 Cppflags []string 99 Lto struct { 100 Never *bool 101 } 102 Sanitize struct { 103 Address *bool 104 } 105 } 106 107 Pdk struct { 108 Enabled *bool `android:"arch_variant"` 109 } `android:"arch_variant"` 110 111 Uml struct { 112 Cppflags []string 113 } 114 115 Use_lmkd_stats_log struct { 116 Cflags []string 117 } 118 119 Arc struct { 120 Cflags []string 121 Exclude_srcs []string 122 Include_dirs []string 123 Shared_libs []string 124 Static_libs []string 125 Srcs []string 126 } 127 } `android:"arch_variant"` 128} 129 130var zeroProductVariables variableProperties 131 132type productVariables struct { 133 // Suffix to add to generated Makefiles 134 Make_suffix *string `json:",omitempty"` 135 136 BuildId *string `json:",omitempty"` 137 BuildNumberFromFile *string `json:",omitempty"` 138 DateFromFile *string `json:",omitempty"` 139 140 Platform_version_name *string `json:",omitempty"` 141 Platform_sdk_version *int `json:",omitempty"` 142 Platform_sdk_codename *string `json:",omitempty"` 143 Platform_sdk_final *bool `json:",omitempty"` 144 Platform_version_active_codenames []string `json:",omitempty"` 145 Platform_version_future_codenames []string `json:",omitempty"` 146 Platform_vndk_version *string `json:",omitempty"` 147 Platform_systemsdk_versions []string `json:",omitempty"` 148 Platform_security_patch *string `json:",omitempty"` 149 Platform_preview_sdk_version *string `json:",omitempty"` 150 Platform_min_supported_target_sdk_version *string `json:",omitempty"` 151 Platform_base_os *string `json:",omitempty"` 152 153 DeviceName *string `json:",omitempty"` 154 DeviceArch *string `json:",omitempty"` 155 DeviceArchVariant *string `json:",omitempty"` 156 DeviceCpuVariant *string `json:",omitempty"` 157 DeviceAbi []string `json:",omitempty"` 158 DeviceVndkVersion *string `json:",omitempty"` 159 DeviceSystemSdkVersions []string `json:",omitempty"` 160 161 DeviceSecondaryArch *string `json:",omitempty"` 162 DeviceSecondaryArchVariant *string `json:",omitempty"` 163 DeviceSecondaryCpuVariant *string `json:",omitempty"` 164 DeviceSecondaryAbi []string `json:",omitempty"` 165 166 HostArch *string `json:",omitempty"` 167 HostSecondaryArch *string `json:",omitempty"` 168 169 CrossHost *string `json:",omitempty"` 170 CrossHostArch *string `json:",omitempty"` 171 CrossHostSecondaryArch *string `json:",omitempty"` 172 173 DeviceResourceOverlays []string `json:",omitempty"` 174 ProductResourceOverlays []string `json:",omitempty"` 175 EnforceRROTargets []string `json:",omitempty"` 176 EnforceRROExcludedOverlays []string `json:",omitempty"` 177 178 AAPTCharacteristics *string `json:",omitempty"` 179 AAPTConfig []string `json:",omitempty"` 180 AAPTPreferredConfig *string `json:",omitempty"` 181 AAPTPrebuiltDPI []string `json:",omitempty"` 182 183 DefaultAppCertificate *string `json:",omitempty"` 184 185 AppsDefaultVersionName *string `json:",omitempty"` 186 187 Allow_missing_dependencies *bool `json:",omitempty"` 188 Unbundled_build *bool `json:",omitempty"` 189 Unbundled_build_sdks_from_source *bool `json:",omitempty"` 190 Malloc_not_svelte *bool `json:",omitempty"` 191 Safestack *bool `json:",omitempty"` 192 HostStaticBinaries *bool `json:",omitempty"` 193 Binder32bit *bool `json:",omitempty"` 194 UseGoma *bool `json:",omitempty"` 195 Debuggable *bool `json:",omitempty"` 196 Eng *bool `json:",omitempty"` 197 Treble_linker_namespaces *bool `json:",omitempty"` 198 Enforce_vintf_manifest *bool `json:",omitempty"` 199 Pdk *bool `json:",omitempty"` 200 Uml *bool `json:",omitempty"` 201 Use_lmkd_stats_log *bool `json:",omitempty"` 202 Arc *bool `json:",omitempty"` 203 MinimizeJavaDebugInfo *bool `json:",omitempty"` 204 205 Check_elf_files *bool `json:",omitempty"` 206 207 UncompressPrivAppDex *bool `json:",omitempty"` 208 ModulesLoadedByPrivilegedModules []string `json:",omitempty"` 209 210 BootJars []string `json:",omitempty"` 211 212 IntegerOverflowExcludePaths []string `json:",omitempty"` 213 214 EnableCFI *bool `json:",omitempty"` 215 CFIExcludePaths []string `json:",omitempty"` 216 CFIIncludePaths []string `json:",omitempty"` 217 218 DisableScudo *bool `json:",omitempty"` 219 220 EnableXOM *bool `json:",omitempty"` 221 XOMExcludePaths []string `json:",omitempty"` 222 223 VendorPath *string `json:",omitempty"` 224 OdmPath *string `json:",omitempty"` 225 ProductPath *string `json:",omitempty"` 226 ProductServicesPath *string `json:",omitempty"` 227 228 ClangTidy *bool `json:",omitempty"` 229 TidyChecks *string `json:",omitempty"` 230 231 NativeCoverage *bool `json:",omitempty"` 232 CoveragePaths []string `json:",omitempty"` 233 CoverageExcludePaths []string `json:",omitempty"` 234 235 DevicePrefer32BitApps *bool `json:",omitempty"` 236 DevicePrefer32BitExecutables *bool `json:",omitempty"` 237 HostPrefer32BitExecutables *bool `json:",omitempty"` 238 239 SanitizeHost []string `json:",omitempty"` 240 SanitizeDevice []string `json:",omitempty"` 241 SanitizeDeviceDiag []string `json:",omitempty"` 242 SanitizeDeviceArch []string `json:",omitempty"` 243 244 ArtUseReadBarrier *bool `json:",omitempty"` 245 246 BtConfigIncludeDir *string `json:",omitempty"` 247 248 Override_rs_driver *string `json:",omitempty"` 249 250 Product_is_iot *bool `json:",omitempty"` 251 252 Fuchsia *bool `json:",omitempty"` 253 254 DeviceKernelHeaders []string `json:",omitempty"` 255 256 ExtraVndkVersions []string `json:",omitempty"` 257 258 NamespacesToExport []string `json:",omitempty"` 259 260 PgoAdditionalProfileDirs []string `json:",omitempty"` 261 262 VndkUseCoreVariant *bool `json:",omitempty"` 263 264 BoardVendorSepolicyDirs []string `json:",omitempty"` 265 BoardOdmSepolicyDirs []string `json:",omitempty"` 266 BoardPlatPublicSepolicyDirs []string `json:",omitempty"` 267 BoardPlatPrivateSepolicyDirs []string `json:",omitempty"` 268 269 VendorVars map[string]map[string]string `json:",omitempty"` 270 271 Ndk_abis *bool `json:",omitempty"` 272 Exclude_draft_ndk_apis *bool `json:",omitempty"` 273 274 FlattenApex *bool `json:",omitempty"` 275 276 DexpreoptGlobalConfig *string `json:",omitempty"` 277 278 ManifestPackageNameOverrides []string `json:",omitempty"` 279 CertificateOverrides []string `json:",omitempty"` 280 PackageNameOverrides []string `json:",omitempty"` 281 282 EnforceSystemCertificate *bool `json:",omitempty"` 283 EnforceSystemCertificateWhitelist []string `json:",omitempty"` 284 285 ProductHiddenAPIStubs []string `json:",omitempty"` 286 ProductHiddenAPIStubsSystem []string `json:",omitempty"` 287 ProductHiddenAPIStubsTest []string `json:",omitempty"` 288 289 TargetFSConfigGen []string `json:",omitempty"` 290} 291 292func boolPtr(v bool) *bool { 293 return &v 294} 295 296func intPtr(v int) *int { 297 return &v 298} 299 300func stringPtr(v string) *string { 301 return &v 302} 303 304func (v *productVariables) SetDefaultConfig() { 305 *v = productVariables{ 306 Platform_sdk_version: intPtr(26), 307 Platform_version_active_codenames: []string{"P"}, 308 Platform_version_future_codenames: []string{"P"}, 309 310 HostArch: stringPtr("x86_64"), 311 HostSecondaryArch: stringPtr("x86"), 312 DeviceName: stringPtr("generic_arm64"), 313 DeviceArch: stringPtr("arm64"), 314 DeviceArchVariant: stringPtr("armv8-a"), 315 DeviceCpuVariant: stringPtr("generic"), 316 DeviceAbi: []string{"arm64-v8a"}, 317 DeviceSecondaryArch: stringPtr("arm"), 318 DeviceSecondaryArchVariant: stringPtr("armv8-a"), 319 DeviceSecondaryCpuVariant: stringPtr("generic"), 320 DeviceSecondaryAbi: []string{"armeabi-v7a", "armeabi"}, 321 322 AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"}, 323 AAPTPreferredConfig: stringPtr("xhdpi"), 324 AAPTCharacteristics: stringPtr("nosdcard"), 325 AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"}, 326 327 Malloc_not_svelte: boolPtr(true), 328 Safestack: boolPtr(false), 329 } 330 331 if runtime.GOOS == "linux" { 332 v.CrossHost = stringPtr("windows") 333 v.CrossHostArch = stringPtr("x86") 334 v.CrossHostSecondaryArch = stringPtr("x86_64") 335 } 336} 337 338func variableMutator(mctx BottomUpMutatorContext) { 339 var module Module 340 var ok bool 341 if module, ok = mctx.Module().(Module); !ok { 342 return 343 } 344 345 // TODO: depend on config variable, create variants, propagate variants up tree 346 a := module.base() 347 variableValues := reflect.ValueOf(&a.variableProperties.Product_variables).Elem() 348 zeroValues := reflect.ValueOf(zeroProductVariables.Product_variables) 349 350 for i := 0; i < variableValues.NumField(); i++ { 351 variableValue := variableValues.Field(i) 352 zeroValue := zeroValues.Field(i) 353 name := variableValues.Type().Field(i).Name 354 property := "product_variables." + proptools.PropertyNameForField(name) 355 356 // Check that the variable was set for the product 357 val := reflect.ValueOf(mctx.Config().productVariables).FieldByName(name) 358 if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() { 359 continue 360 } 361 362 val = val.Elem() 363 364 // For bools, check that the value is true 365 if val.Kind() == reflect.Bool && val.Bool() == false { 366 continue 367 } 368 369 // Check if any properties were set for the module 370 if reflect.DeepEqual(variableValue.Interface(), zeroValue.Interface()) { 371 continue 372 } 373 374 a.setVariableProperties(mctx, property, variableValue, val.Interface()) 375 } 376} 377 378func (a *ModuleBase) setVariableProperties(ctx BottomUpMutatorContext, 379 prefix string, productVariablePropertyValue reflect.Value, variableValue interface{}) { 380 381 printfIntoProperties(ctx, prefix, productVariablePropertyValue, variableValue) 382 383 err := proptools.AppendMatchingProperties(a.generalProperties, 384 productVariablePropertyValue.Addr().Interface(), nil) 385 if err != nil { 386 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 387 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 388 } else { 389 panic(err) 390 } 391 } 392} 393 394func printfIntoPropertiesError(ctx BottomUpMutatorContext, prefix string, 395 productVariablePropertyValue reflect.Value, i int, err error) { 396 397 field := productVariablePropertyValue.Type().Field(i).Name 398 property := prefix + "." + proptools.PropertyNameForField(field) 399 ctx.PropertyErrorf(property, "%s", err) 400} 401 402func printfIntoProperties(ctx BottomUpMutatorContext, prefix string, 403 productVariablePropertyValue reflect.Value, variableValue interface{}) { 404 405 for i := 0; i < productVariablePropertyValue.NumField(); i++ { 406 propertyValue := productVariablePropertyValue.Field(i) 407 kind := propertyValue.Kind() 408 if kind == reflect.Ptr { 409 if propertyValue.IsNil() { 410 continue 411 } 412 propertyValue = propertyValue.Elem() 413 } 414 switch propertyValue.Kind() { 415 case reflect.String: 416 err := printfIntoProperty(propertyValue, variableValue) 417 if err != nil { 418 printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err) 419 } 420 case reflect.Slice: 421 for j := 0; j < propertyValue.Len(); j++ { 422 err := printfIntoProperty(propertyValue.Index(j), variableValue) 423 if err != nil { 424 printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err) 425 } 426 } 427 case reflect.Bool: 428 // Nothing 429 case reflect.Struct: 430 printfIntoProperties(ctx, prefix, propertyValue, variableValue) 431 default: 432 panic(fmt.Errorf("unsupported field kind %q", propertyValue.Kind())) 433 } 434 } 435} 436 437func printfIntoProperty(propertyValue reflect.Value, variableValue interface{}) error { 438 s := propertyValue.String() 439 440 count := strings.Count(s, "%") 441 if count == 0 { 442 return nil 443 } 444 445 if count > 1 { 446 return fmt.Errorf("product variable properties only support a single '%%'") 447 } 448 449 if strings.Contains(s, "%d") { 450 switch v := variableValue.(type) { 451 case int: 452 // Nothing 453 case bool: 454 if v { 455 variableValue = 1 456 } else { 457 variableValue = 0 458 } 459 default: 460 return fmt.Errorf("unsupported type %T for %%d", variableValue) 461 } 462 } else if strings.Contains(s, "%s") { 463 switch variableValue.(type) { 464 case string: 465 // Nothing 466 default: 467 return fmt.Errorf("unsupported type %T for %%s", variableValue) 468 } 469 } else { 470 return fmt.Errorf("unsupported %% in product variable property") 471 } 472 473 propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, variableValue))) 474 475 return nil 476} 477