1// Copyright 2017 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 15// This file implements the logic of bpfix and also provides a programmatic interface 16 17package bpfix 18 19import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "io" 24 "path/filepath" 25 "strings" 26 27 "github.com/google/blueprint/parser" 28) 29 30// Reformat takes a blueprint file as a string and returns a formatted version 31func Reformat(input string) (string, error) { 32 tree, err := parse("<string>", bytes.NewBufferString(input)) 33 if err != nil { 34 return "", err 35 } 36 37 res, err := parser.Print(tree) 38 if err != nil { 39 return "", err 40 } 41 42 return string(res), nil 43} 44 45// A FixRequest specifies the details of which fixes to apply to an individual file 46// A FixRequest doesn't specify whether to do a dry run or where to write the results; that's in cmd/bpfix.go 47type FixRequest struct { 48 steps []FixStep 49} 50type FixStepsExtension struct { 51 Name string 52 Steps []FixStep 53} 54 55type FixStep struct { 56 Name string 57 Fix func(f *Fixer) error 58} 59 60var fixStepsExtensions = []*FixStepsExtension(nil) 61 62func RegisterFixStepExtension(extension *FixStepsExtension) { 63 fixStepsExtensions = append(fixStepsExtensions, extension) 64} 65 66var fixSteps = []FixStep{ 67 { 68 Name: "simplifyKnownRedundantVariables", 69 Fix: runPatchListMod(simplifyKnownPropertiesDuplicatingEachOther), 70 }, 71 { 72 Name: "rewriteIncorrectAndroidmkPrebuilts", 73 Fix: rewriteIncorrectAndroidmkPrebuilts, 74 }, 75 { 76 Name: "rewriteCtsModuleTypes", 77 Fix: rewriteCtsModuleTypes, 78 }, 79 { 80 Name: "rewriteIncorrectAndroidmkAndroidLibraries", 81 Fix: rewriteIncorrectAndroidmkAndroidLibraries, 82 }, 83 { 84 Name: "rewriteTestModuleTypes", 85 Fix: rewriteTestModuleTypes, 86 }, 87 { 88 Name: "rewriteAndroidmkJavaLibs", 89 Fix: rewriteAndroidmkJavaLibs, 90 }, 91 { 92 Name: "rewriteJavaStaticLibs", 93 Fix: rewriteJavaStaticLibs, 94 }, 95 { 96 Name: "rewritePrebuiltEtc", 97 Fix: rewriteAndroidmkPrebuiltEtc, 98 }, 99 { 100 Name: "mergeMatchingModuleProperties", 101 Fix: runPatchListMod(mergeMatchingModuleProperties), 102 }, 103 { 104 Name: "reorderCommonProperties", 105 Fix: runPatchListMod(reorderCommonProperties), 106 }, 107 { 108 Name: "removeTags", 109 Fix: runPatchListMod(removeTags), 110 }, 111 { 112 Name: "rewriteAndroidTest", 113 Fix: rewriteAndroidTest, 114 }, 115 { 116 Name: "rewriteAndroidAppImport", 117 Fix: rewriteAndroidAppImport, 118 }, 119 { 120 Name: "removeEmptyLibDependencies", 121 Fix: removeEmptyLibDependencies, 122 }, 123 { 124 Name: "removeHidlInterfaceTypes", 125 Fix: removeHidlInterfaceTypes, 126 }, 127 { 128 Name: "removeSoongConfigBoolVariable", 129 Fix: removeSoongConfigBoolVariable, 130 }, 131} 132 133func NewFixRequest() FixRequest { 134 return FixRequest{} 135} 136 137func (r FixRequest) AddAll() (result FixRequest) { 138 result.steps = append([]FixStep(nil), r.steps...) 139 result.steps = append(result.steps, fixSteps...) 140 for _, extension := range fixStepsExtensions { 141 result.steps = append(result.steps, extension.Steps...) 142 } 143 return result 144} 145 146func (r FixRequest) AddBase() (result FixRequest) { 147 result.steps = append([]FixStep(nil), r.steps...) 148 result.steps = append(result.steps, fixSteps...) 149 return result 150} 151 152func (r FixRequest) AddMatchingExtensions(pattern string) (result FixRequest) { 153 result.steps = append([]FixStep(nil), r.steps...) 154 for _, extension := range fixStepsExtensions { 155 if match, _ := filepath.Match(pattern, extension.Name); match { 156 result.steps = append(result.steps, extension.Steps...) 157 } 158 } 159 return result 160} 161 162type Fixer struct { 163 tree *parser.File 164} 165 166func (f Fixer) Tree() *parser.File { 167 return f.tree 168} 169 170func NewFixer(tree *parser.File) *Fixer { 171 fixer := &Fixer{tree} 172 173 // make a copy of the tree 174 fixer.reparse() 175 176 return fixer 177} 178 179// Fix repeatedly applies the fixes listed in the given FixRequest to the given File 180// until there is no fix that affects the tree 181func (f *Fixer) Fix(config FixRequest) (*parser.File, error) { 182 prevIdentifier, err := f.fingerprint() 183 if err != nil { 184 return nil, err 185 } 186 187 maxNumIterations := 20 188 i := 0 189 for { 190 err = f.fixTreeOnce(config) 191 newIdentifier, err := f.fingerprint() 192 if err != nil { 193 return nil, err 194 } 195 if bytes.Equal(newIdentifier, prevIdentifier) { 196 break 197 } 198 prevIdentifier = newIdentifier 199 // any errors from a previous iteration generally get thrown away and overwritten by errors on the next iteration 200 201 // detect infinite loop 202 i++ 203 if i >= maxNumIterations { 204 return nil, fmt.Errorf("Applied fixes %d times and yet the tree continued to change. Is there an infinite loop?", i) 205 } 206 } 207 return f.tree, err 208} 209 210// returns a unique identifier for the given tree that can be used to determine whether the tree changed 211func (f *Fixer) fingerprint() (fingerprint []byte, err error) { 212 bytes, err := parser.Print(f.tree) 213 if err != nil { 214 return nil, err 215 } 216 return bytes, nil 217} 218 219func (f *Fixer) reparse() ([]byte, error) { 220 buf, err := parser.Print(f.tree) 221 if err != nil { 222 return nil, err 223 } 224 newTree, err := parse(f.tree.Name, bytes.NewReader(buf)) 225 if err != nil { 226 return nil, err 227 } 228 f.tree = newTree 229 return buf, nil 230} 231 232func parse(name string, r io.Reader) (*parser.File, error) { 233 tree, errs := parser.Parse(name, r, parser.NewScope(nil)) 234 if errs != nil { 235 s := "parse error: " 236 for _, err := range errs { 237 s += "\n" + err.Error() 238 } 239 return nil, errors.New(s) 240 } 241 return tree, nil 242} 243 244func (f *Fixer) fixTreeOnce(config FixRequest) error { 245 for _, fix := range config.steps { 246 err := fix.Fix(f) 247 if err != nil { 248 return err 249 } 250 } 251 return nil 252} 253 254func simplifyKnownPropertiesDuplicatingEachOther(mod *parser.Module, buf []byte, patchList *parser.PatchList) error { 255 // remove from local_include_dirs anything in export_include_dirs 256 return removeMatchingModuleListProperties(mod, patchList, 257 "export_include_dirs", "local_include_dirs") 258} 259 260func rewriteIncorrectAndroidmkPrebuilts(f *Fixer) error { 261 for _, def := range f.tree.Defs { 262 mod, ok := def.(*parser.Module) 263 if !ok { 264 continue 265 } 266 if mod.Type != "java_import" { 267 continue 268 } 269 host, _ := getLiteralBoolPropertyValue(mod, "host") 270 if host { 271 mod.Type = "java_import_host" 272 removeProperty(mod, "host") 273 } 274 srcs, ok := getLiteralListProperty(mod, "srcs") 275 if !ok { 276 continue 277 } 278 if len(srcs.Values) == 0 { 279 continue 280 } 281 src, ok := srcs.Values[0].(*parser.String) 282 if !ok { 283 continue 284 } 285 switch filepath.Ext(src.Value) { 286 case ".jar": 287 renameProperty(mod, "srcs", "jars") 288 289 case ".aar": 290 renameProperty(mod, "srcs", "aars") 291 mod.Type = "android_library_import" 292 293 // An android_library_import doesn't get installed, so setting "installable = false" isn't supported 294 removeProperty(mod, "installable") 295 } 296 } 297 298 return nil 299} 300 301func rewriteCtsModuleTypes(f *Fixer) error { 302 for _, def := range f.tree.Defs { 303 mod, ok := def.(*parser.Module) 304 if !ok { 305 continue 306 } 307 308 if mod.Type != "cts_support_package" && mod.Type != "cts_package" && 309 mod.Type != "cts_target_java_library" && 310 mod.Type != "cts_host_java_library" { 311 312 continue 313 } 314 315 var defStr string 316 switch mod.Type { 317 case "cts_support_package": 318 mod.Type = "android_test" 319 defStr = "cts_support_defaults" 320 case "cts_package": 321 mod.Type = "android_test" 322 defStr = "cts_defaults" 323 case "cts_target_java_library": 324 mod.Type = "java_library" 325 defStr = "cts_defaults" 326 case "cts_host_java_library": 327 mod.Type = "java_library_host" 328 defStr = "cts_defaults" 329 } 330 331 defaults := &parser.Property{ 332 Name: "defaults", 333 Value: &parser.List{ 334 Values: []parser.Expression{ 335 &parser.String{ 336 Value: defStr, 337 }, 338 }, 339 }, 340 } 341 mod.Properties = append(mod.Properties, defaults) 342 } 343 344 return nil 345} 346 347func rewriteIncorrectAndroidmkAndroidLibraries(f *Fixer) error { 348 for _, def := range f.tree.Defs { 349 mod, ok := def.(*parser.Module) 350 if !ok { 351 continue 352 } 353 354 if !strings.HasPrefix(mod.Type, "java_") && !strings.HasPrefix(mod.Type, "android_") { 355 continue 356 } 357 358 hasAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_libs") 359 hasStaticAndroidLibraries := hasNonEmptyLiteralListProperty(mod, "android_static_libs") 360 hasResourceDirs := hasNonEmptyLiteralListProperty(mod, "resource_dirs") 361 362 if hasAndroidLibraries || hasStaticAndroidLibraries || hasResourceDirs { 363 if mod.Type == "java_library_static" || mod.Type == "java_library" { 364 mod.Type = "android_library" 365 } 366 } 367 368 if mod.Type == "java_import" && !hasStaticAndroidLibraries { 369 removeProperty(mod, "android_static_libs") 370 } 371 372 // These may conflict with existing libs and static_libs properties, but the 373 // mergeMatchingModuleProperties pass will fix it. 374 renameProperty(mod, "shared_libs", "libs") 375 renameProperty(mod, "android_libs", "libs") 376 renameProperty(mod, "android_static_libs", "static_libs") 377 } 378 379 return nil 380} 381 382// rewriteTestModuleTypes looks for modules that are identifiable as tests but for which Make doesn't have a separate 383// module class, and moves them to the appropriate Soong module type. 384func rewriteTestModuleTypes(f *Fixer) error { 385 for _, def := range f.tree.Defs { 386 mod, ok := def.(*parser.Module) 387 if !ok { 388 continue 389 } 390 391 if !strings.HasPrefix(mod.Type, "java_") && !strings.HasPrefix(mod.Type, "android_") { 392 continue 393 } 394 395 hasInstrumentationFor := hasNonEmptyLiteralStringProperty(mod, "instrumentation_for") 396 tags, _ := getLiteralListPropertyValue(mod, "tags") 397 398 var hasTestsTag bool 399 for _, tag := range tags { 400 if tag == "tests" { 401 hasTestsTag = true 402 } 403 } 404 405 isTest := hasInstrumentationFor || hasTestsTag 406 407 if isTest { 408 switch mod.Type { 409 case "android_app": 410 mod.Type = "android_test" 411 case "android_app_import": 412 mod.Type = "android_test_import" 413 case "java_library", "java_library_installable": 414 mod.Type = "java_test" 415 case "java_library_host": 416 mod.Type = "java_test_host" 417 } 418 } 419 } 420 421 return nil 422} 423 424// rewriteJavaStaticLibs rewrites java_library_static into java_library 425func rewriteJavaStaticLibs(f *Fixer) error { 426 for _, def := range f.tree.Defs { 427 mod, ok := def.(*parser.Module) 428 if !ok { 429 continue 430 } 431 432 if mod.Type == "java_library_static" { 433 mod.Type = "java_library" 434 } 435 } 436 437 return nil 438} 439 440// rewriteAndroidmkJavaLibs rewrites java_library_installable into java_library plus installable: true 441func rewriteAndroidmkJavaLibs(f *Fixer) error { 442 for _, def := range f.tree.Defs { 443 mod, ok := def.(*parser.Module) 444 if !ok { 445 continue 446 } 447 448 if mod.Type != "java_library_installable" { 449 continue 450 } 451 452 mod.Type = "java_library" 453 454 _, hasInstallable := mod.GetProperty("installable") 455 if !hasInstallable { 456 prop := &parser.Property{ 457 Name: "installable", 458 Value: &parser.Bool{ 459 Value: true, 460 }, 461 } 462 mod.Properties = append(mod.Properties, prop) 463 } 464 } 465 466 return nil 467} 468 469// Helper function to get the value of a string-valued property in a given compound property. 470func getStringProperty(prop *parser.Property, fieldName string) string { 471 if propsAsMap, ok := prop.Value.(*parser.Map); ok { 472 for _, propField := range propsAsMap.Properties { 473 if fieldName == propField.Name { 474 if propFieldAsString, ok := propField.Value.(*parser.String); ok { 475 return propFieldAsString.Value 476 } else { 477 return "" 478 } 479 } 480 } 481 } 482 return "" 483} 484 485// Set the value of the given attribute to the error message 486func indicateAttributeError(mod *parser.Module, attributeName string, format string, a ...interface{}) error { 487 msg := fmt.Sprintf(format, a...) 488 mod.Properties = append(mod.Properties, &parser.Property{ 489 Name: attributeName, 490 Value: &parser.String{Value: "ERROR: " + msg}, 491 }) 492 return errors.New(msg) 493} 494 495// If a variable is LOCAL_MODULE, get its value from the 'name' attribute. 496// This handles the statement 497// LOCAL_SRC_FILES := $(LOCAL_MODULE) 498// which occurs often. 499func resolveLocalModule(mod *parser.Module, val parser.Expression) parser.Expression { 500 if varLocalName, ok := val.(*parser.Variable); ok { 501 if varLocalName.Name == "LOCAL_MODULE" { 502 if v, ok := getLiteralStringProperty(mod, "name"); ok { 503 return v 504 } 505 } 506 } 507 return val 508} 509 510// etcPrebuiltModuleUpdate contains information on updating certain parts of a defined module such as: 511// * changing the module type from prebuilt_etc to a different one 512// * stripping the prefix of the install path based on the module type 513// * appending additional boolean properties to the prebuilt module 514type etcPrebuiltModuleUpdate struct { 515 // The prefix of the install path defined in local_module_path. The prefix is removed from local_module_path 516 // before setting the 'filename' attribute. 517 prefix string 518 519 // There is only one prebuilt module type in makefiles. In Soong, there are multiple versions of 520 // prebuilts based on local_module_path. By default, it is "prebuilt_etc" if modType is blank. An 521 // example is if the local_module_path contains $(TARGET_OUT)/usr/share, the module type is 522 // considered as prebuilt_usr_share. 523 modType string 524 525 // Additional boolean attributes to be added in the prebuilt module. Each added boolean attribute 526 // has a value of true. 527 flags []string 528} 529 530func (f etcPrebuiltModuleUpdate) update(m *parser.Module, path string) bool { 531 updated := false 532 if path == f.prefix { 533 updated = true 534 } else if trimmedPath := strings.TrimPrefix(path, f.prefix+"/"); trimmedPath != path { 535 m.Properties = append(m.Properties, &parser.Property{ 536 Name: "relative_install_path", 537 Value: &parser.String{Value: trimmedPath}, 538 }) 539 updated = true 540 } 541 if updated { 542 for _, flag := range f.flags { 543 m.Properties = append(m.Properties, &parser.Property{Name: flag, Value: &parser.Bool{Value: true, Token: "true"}}) 544 } 545 if f.modType != "" { 546 m.Type = f.modType 547 } 548 } 549 return updated 550} 551 552var localModuleUpdate = map[string][]etcPrebuiltModuleUpdate{ 553 "HOST_OUT": {{prefix: "/etc", modType: "prebuilt_etc_host"}, {prefix: "/usr/share", modType: "prebuilt_usr_share_host"}}, 554 "PRODUCT_OUT": {{prefix: "/system/etc"}, {prefix: "/vendor/etc", flags: []string{"proprietary"}}}, 555 "TARGET_OUT": {{prefix: "/usr/share", modType: "prebuilt_usr_share"}, {prefix: "/fonts", modType: "prebuilt_font"}, 556 {prefix: "/etc/firmware", modType: "prebuilt_firmware"}, {prefix: "/vendor/firmware", modType: "prebuilt_firmware", flags: []string{"proprietary"}}, 557 {prefix: "/etc"}}, 558 "TARGET_OUT_ETC": {{prefix: "/firmware", modType: "prebuilt_firmware"}, {prefix: ""}}, 559 "TARGET_OUT_PRODUCT": {{prefix: "/etc", flags: []string{"product_specific"}}, {prefix: "/fonts", modType: "prebuilt_font", flags: []string{"product_specific"}}}, 560 "TARGET_OUT_PRODUCT_ETC": {{prefix: "", flags: []string{"product_specific"}}}, 561 "TARGET_OUT_ODM": {{prefix: "/etc", flags: []string{"device_specific"}}}, 562 "TARGET_OUT_SYSTEM_EXT": {{prefix: "/etc", flags: []string{"system_ext_specific"}}}, 563 "TARGET_OUT_SYSTEM_EXT_ETC": {{prefix: "", flags: []string{"system_ext_specific"}}}, 564 "TARGET_OUT_VENDOR": {{prefix: "/etc", flags: []string{"proprietary"}}, {prefix: "/firmware", modType: "prebuilt_firmware", flags: []string{"proprietary"}}}, 565 "TARGET_OUT_VENDOR_ETC": {{prefix: "", flags: []string{"proprietary"}}}, 566 "TARGET_RECOVERY_ROOT_OUT": {{prefix: "/system/etc", flags: []string{"recovery"}}}, 567} 568 569// rewriteAndroidPrebuiltEtc fixes prebuilt_etc rule 570func rewriteAndroidmkPrebuiltEtc(f *Fixer) error { 571 for _, def := range f.tree.Defs { 572 mod, ok := def.(*parser.Module) 573 if !ok { 574 continue 575 } 576 577 if mod.Type != "prebuilt_etc" && mod.Type != "prebuilt_etc_host" { 578 continue 579 } 580 581 // 'srcs' --> 'src' conversion 582 convertToSingleSource(mod, "src") 583 584 renameProperty(mod, "sub_dir", "relative_install_dir") 585 586 // The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute 587 // 'local_module_path'. Analyze its contents and create the correct sub_dir:, 588 // filename: and boolean attributes combination 589 const local_module_path = "local_module_path" 590 if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok { 591 removeProperty(mod, local_module_path) 592 prefixVariableName := getStringProperty(prop_local_module_path, "var") 593 if moduleUpdates, ok := localModuleUpdate[prefixVariableName]; ok { 594 path := getStringProperty(prop_local_module_path, "fixed") 595 updated := false 596 for i := 0; i < len(moduleUpdates) && !updated; i++ { 597 updated = moduleUpdates[i].update(mod, path) 598 } 599 if !updated { 600 expectedPrefices := "" 601 sep := "" 602 for _, moduleUpdate := range moduleUpdates { 603 expectedPrefices += sep 604 sep = ", " 605 expectedPrefices += moduleUpdate.prefix 606 } 607 return indicateAttributeError(mod, "filename", 608 "LOCAL_MODULE_PATH value under $(%s) should start with %s", prefixVariableName, expectedPrefices) 609 } 610 } else { 611 return indicateAttributeError(mod, "filename", "Cannot handle $(%s) for the prebuilt_etc", prefixVariableName) 612 } 613 } 614 } 615 return nil 616} 617 618func rewriteAndroidTest(f *Fixer) error { 619 for _, def := range f.tree.Defs { 620 mod, ok := def.(*parser.Module) 621 if !(ok && mod.Type == "android_test") { 622 continue 623 } 624 // The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute 625 // 'local_module_path'. For the android_test module, it should be $(TARGET_OUT_DATA_APPS), 626 // that is, `local_module_path: { var: "TARGET_OUT_DATA_APPS"}` 627 const local_module_path = "local_module_path" 628 if prop_local_module_path, ok := mod.GetProperty(local_module_path); ok { 629 removeProperty(mod, local_module_path) 630 prefixVariableName := getStringProperty(prop_local_module_path, "var") 631 path := getStringProperty(prop_local_module_path, "fixed") 632 if prefixVariableName == "TARGET_OUT_DATA_APPS" && path == "" { 633 continue 634 } 635 return indicateAttributeError(mod, "filename", 636 "Only LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) is allowed for the android_test") 637 } 638 } 639 return nil 640} 641 642func rewriteAndroidAppImport(f *Fixer) error { 643 for _, def := range f.tree.Defs { 644 mod, ok := def.(*parser.Module) 645 if !(ok && mod.Type == "android_app_import") { 646 continue 647 } 648 // 'srcs' --> 'apk' conversion 649 convertToSingleSource(mod, "apk") 650 // Handle special certificate value, "PRESIGNED". 651 if cert, ok := mod.GetProperty("certificate"); ok { 652 if certStr, ok := cert.Value.(*parser.String); ok { 653 if certStr.Value == "PRESIGNED" { 654 removeProperty(mod, "certificate") 655 prop := &parser.Property{ 656 Name: "presigned", 657 Value: &parser.Bool{ 658 Value: true, 659 }, 660 } 661 mod.Properties = append(mod.Properties, prop) 662 } 663 } 664 } 665 } 666 return nil 667} 668 669// Removes library dependencies which are empty (and restricted from usage in Soong) 670func removeEmptyLibDependencies(f *Fixer) error { 671 emptyLibraries := []string{ 672 "libhidltransport", 673 "libhwbinder", 674 } 675 relevantFields := []string{ 676 "export_shared_lib_headers", 677 "export_static_lib_headers", 678 "static_libs", 679 "whole_static_libs", 680 "shared_libs", 681 } 682 for _, def := range f.tree.Defs { 683 mod, ok := def.(*parser.Module) 684 if !ok { 685 continue 686 } 687 for _, field := range relevantFields { 688 listValue, ok := getLiteralListProperty(mod, field) 689 if !ok { 690 continue 691 } 692 newValues := []parser.Expression{} 693 for _, v := range listValue.Values { 694 stringValue, ok := v.(*parser.String) 695 if !ok { 696 return fmt.Errorf("Expecting string for %s.%s fields", mod.Type, field) 697 } 698 if inList(stringValue.Value, emptyLibraries) { 699 continue 700 } 701 newValues = append(newValues, stringValue) 702 } 703 if len(newValues) == 0 && len(listValue.Values) != 0 { 704 removeProperty(mod, field) 705 } else { 706 listValue.Values = newValues 707 } 708 } 709 } 710 return nil 711} 712 713// Removes hidl_interface 'types' which are no longer needed 714func removeHidlInterfaceTypes(f *Fixer) error { 715 for _, def := range f.tree.Defs { 716 mod, ok := def.(*parser.Module) 717 if !(ok && mod.Type == "hidl_interface") { 718 continue 719 } 720 removeProperty(mod, "types") 721 } 722 return nil 723} 724 725func removeSoongConfigBoolVariable(f *Fixer) error { 726 found := map[string]bool{} 727 newDefs := make([]parser.Definition, 0, len(f.tree.Defs)) 728 for _, def := range f.tree.Defs { 729 if mod, ok := def.(*parser.Module); ok && mod.Type == "soong_config_bool_variable" { 730 if name, ok := getLiteralStringPropertyValue(mod, "name"); ok { 731 found[name] = true 732 } else { 733 return fmt.Errorf("Found soong_config_bool_variable without a name") 734 } 735 } else { 736 newDefs = append(newDefs, def) 737 } 738 } 739 f.tree.Defs = newDefs 740 741 if len(found) == 0 { 742 return nil 743 } 744 745 return runPatchListMod(func(mod *parser.Module, buf []byte, patchList *parser.PatchList) error { 746 if mod.Type != "soong_config_module_type" { 747 return nil 748 } 749 750 variables, ok := getLiteralListProperty(mod, "variables") 751 if !ok { 752 return nil 753 } 754 755 boolValues := strings.Builder{} 756 empty := true 757 for _, item := range variables.Values { 758 nameValue, ok := item.(*parser.String) 759 if !ok { 760 empty = false 761 continue 762 } 763 if found[nameValue.Value] { 764 patchList.Add(item.Pos().Offset, item.End().Offset+2, "") 765 766 boolValues.WriteString(`"`) 767 boolValues.WriteString(nameValue.Value) 768 boolValues.WriteString(`",`) 769 } else { 770 empty = false 771 } 772 } 773 if empty { 774 *patchList = parser.PatchList{} 775 776 prop, _ := mod.GetProperty("variables") 777 patchList.Add(prop.Pos().Offset, prop.End().Offset+2, "") 778 } 779 if boolValues.Len() == 0 { 780 return nil 781 } 782 783 bool_variables, ok := getLiteralListProperty(mod, "bool_variables") 784 if ok { 785 patchList.Add(bool_variables.RBracePos.Offset, bool_variables.RBracePos.Offset, ","+boolValues.String()) 786 } else { 787 patchList.Add(variables.RBracePos.Offset+2, variables.RBracePos.Offset+2, 788 fmt.Sprintf(`bool_variables: [%s],`, boolValues.String())) 789 } 790 791 return nil 792 })(f) 793 794 return nil 795} 796 797// Converts the default source list property, 'srcs', to a single source property with a given name. 798// "LOCAL_MODULE" reference is also resolved during the conversion process. 799func convertToSingleSource(mod *parser.Module, srcPropertyName string) { 800 if srcs, ok := mod.GetProperty("srcs"); ok { 801 if srcList, ok := srcs.Value.(*parser.List); ok { 802 removeProperty(mod, "srcs") 803 if len(srcList.Values) == 1 { 804 mod.Properties = append(mod.Properties, 805 &parser.Property{ 806 Name: srcPropertyName, 807 NamePos: srcs.NamePos, 808 ColonPos: srcs.ColonPos, 809 Value: resolveLocalModule(mod, srcList.Values[0])}) 810 } else if len(srcList.Values) > 1 { 811 indicateAttributeError(mod, srcPropertyName, "LOCAL_SRC_FILES should contain at most one item") 812 } 813 } else if _, ok = srcs.Value.(*parser.Variable); ok { 814 removeProperty(mod, "srcs") 815 mod.Properties = append(mod.Properties, 816 &parser.Property{Name: srcPropertyName, 817 NamePos: srcs.NamePos, 818 ColonPos: srcs.ColonPos, 819 Value: resolveLocalModule(mod, srcs.Value)}) 820 } else { 821 renameProperty(mod, "srcs", "apk") 822 } 823 } 824} 825 826func runPatchListMod(modFunc func(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error) func(*Fixer) error { 827 return func(f *Fixer) error { 828 // Make sure all the offsets are accurate 829 buf, err := f.reparse() 830 if err != nil { 831 return err 832 } 833 834 var patchlist parser.PatchList 835 for _, def := range f.tree.Defs { 836 mod, ok := def.(*parser.Module) 837 if !ok { 838 continue 839 } 840 841 err := modFunc(mod, buf, &patchlist) 842 if err != nil { 843 return err 844 } 845 } 846 847 newBuf := new(bytes.Buffer) 848 err = patchlist.Apply(bytes.NewReader(buf), newBuf) 849 if err != nil { 850 return err 851 } 852 853 // Save a copy of the buffer to print for errors below 854 bufCopy := append([]byte(nil), newBuf.Bytes()...) 855 856 newTree, err := parse(f.tree.Name, newBuf) 857 if err != nil { 858 return fmt.Errorf("Failed to parse: %v\nBuffer:\n%s", err, string(bufCopy)) 859 } 860 861 f.tree = newTree 862 863 return nil 864 } 865} 866 867var commonPropertyPriorities = []string{ 868 "name", 869 "defaults", 870 "device_supported", 871 "host_supported", 872 "installable", 873} 874 875func reorderCommonProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error { 876 if len(mod.Properties) == 0 { 877 return nil 878 } 879 880 pos := mod.LBracePos.Offset + 1 881 stage := "" 882 883 for _, name := range commonPropertyPriorities { 884 idx := propertyIndex(mod.Properties, name) 885 if idx == -1 { 886 continue 887 } 888 if idx == 0 { 889 err := patchlist.Add(pos, pos, stage) 890 if err != nil { 891 return err 892 } 893 stage = "" 894 895 pos = mod.Properties[0].End().Offset + 1 896 mod.Properties = mod.Properties[1:] 897 continue 898 } 899 900 prop := mod.Properties[idx] 901 mod.Properties = append(mod.Properties[:idx], mod.Properties[idx+1:]...) 902 903 stage += string(buf[prop.Pos().Offset : prop.End().Offset+1]) 904 905 err := patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, "") 906 if err != nil { 907 return err 908 } 909 } 910 911 if stage != "" { 912 err := patchlist.Add(pos, pos, stage) 913 if err != nil { 914 return err 915 } 916 } 917 918 return nil 919} 920 921func removeTags(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error { 922 prop, ok := mod.GetProperty("tags") 923 if !ok { 924 return nil 925 } 926 list, ok := prop.Value.(*parser.List) 927 if !ok { 928 return nil 929 } 930 931 replaceStr := "" 932 933 for _, item := range list.Values { 934 str, ok := item.(*parser.String) 935 if !ok { 936 replaceStr += fmt.Sprintf("// ERROR: Unable to parse tag %q\n", item) 937 continue 938 } 939 940 switch str.Value { 941 case "optional": 942 continue 943 case "debug": 944 replaceStr += `// WARNING: Module tags are not supported in Soong. 945 // Add this module to PRODUCT_PACKAGES_DEBUG in your product file if you want to 946 // force installation for -userdebug and -eng builds. 947 ` 948 case "eng": 949 replaceStr += `// WARNING: Module tags are not supported in Soong. 950 // Add this module to PRODUCT_PACKAGES_ENG in your product file if you want to 951 // force installation for -eng builds. 952 ` 953 case "tests": 954 switch { 955 case strings.Contains(mod.Type, "cc_test"), 956 strings.Contains(mod.Type, "cc_library_static"), 957 strings.Contains(mod.Type, "java_test"), 958 mod.Type == "android_test", 959 mod.Type == "android_test_import": 960 continue 961 case strings.Contains(mod.Type, "cc_lib"): 962 replaceStr += `// WARNING: Module tags are not supported in Soong. 963 // To make a shared library only for tests, use the "cc_test_library" module 964 // type. If you don't use gtest, set "gtest: false". 965 ` 966 case strings.Contains(mod.Type, "cc_bin"): 967 replaceStr += `// WARNING: Module tags are not supported in Soong. 968 // For native test binaries, use the "cc_test" module type. Some differences: 969 // - If you don't use gtest, set "gtest: false" 970 // - Binaries will be installed into /data/nativetest[64]/<name>/<name> 971 // - Both 32 & 64 bit versions will be built (as appropriate) 972 ` 973 case strings.Contains(mod.Type, "java_lib"): 974 replaceStr += `// WARNING: Module tags are not supported in Soong. 975 // For JUnit or similar tests, use the "java_test" module type. A dependency on 976 // Junit will be added by default, if it is using some other runner, set "junit: false". 977 ` 978 case mod.Type == "android_app": 979 replaceStr += `// WARNING: Module tags are not supported in Soong. 980 // For JUnit or instrumentataion app tests, use the "android_test" module type. 981 ` 982 default: 983 replaceStr += `// WARNING: Module tags are not supported in Soong. 984 // In most cases, tests are now identified by their module type: 985 // cc_test, java_test, python_test 986 ` 987 } 988 default: 989 replaceStr += fmt.Sprintf("// WARNING: Unknown module tag %q\n", str.Value) 990 } 991 } 992 993 return patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, replaceStr) 994} 995 996func mergeMatchingModuleProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error { 997 return mergeMatchingProperties(&mod.Properties, buf, patchlist) 998} 999 1000func mergeMatchingProperties(properties *[]*parser.Property, buf []byte, patchlist *parser.PatchList) error { 1001 seen := make(map[string]*parser.Property) 1002 for i := 0; i < len(*properties); i++ { 1003 property := (*properties)[i] 1004 if prev, exists := seen[property.Name]; exists { 1005 err := mergeProperties(prev, property, buf, patchlist) 1006 if err != nil { 1007 return err 1008 } 1009 *properties = append((*properties)[:i], (*properties)[i+1:]...) 1010 } else { 1011 seen[property.Name] = property 1012 if mapProperty, ok := property.Value.(*parser.Map); ok { 1013 err := mergeMatchingProperties(&mapProperty.Properties, buf, patchlist) 1014 if err != nil { 1015 return err 1016 } 1017 } 1018 } 1019 } 1020 return nil 1021} 1022 1023func mergeProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error { 1024 // The value of one of the properties may be a variable reference with no type assigned 1025 // Bail out in this case. Soong will notice duplicate entries and will tell to merge them. 1026 if _, isVar := a.Value.(*parser.Variable); isVar { 1027 return nil 1028 } 1029 if _, isVar := b.Value.(*parser.Variable); isVar { 1030 return nil 1031 } 1032 if a.Value.Type() != b.Value.Type() { 1033 return fmt.Errorf("type mismatch when merging properties %q: %s and %s", a.Name, a.Value.Type(), b.Value.Type()) 1034 } 1035 1036 switch a.Value.Type() { 1037 case parser.StringType: 1038 return fmt.Errorf("conflicting definitions of string property %q", a.Name) 1039 case parser.ListType: 1040 return mergeListProperties(a, b, buf, patchlist) 1041 } 1042 1043 return nil 1044} 1045 1046func mergeListProperties(a, b *parser.Property, buf []byte, patchlist *parser.PatchList) error { 1047 aval, oka := a.Value.(*parser.List) 1048 bval, okb := b.Value.(*parser.List) 1049 if !oka || !okb { 1050 // Merging expressions not supported yet 1051 return nil 1052 } 1053 1054 s := string(buf[bval.LBracePos.Offset+1 : bval.RBracePos.Offset]) 1055 if bval.LBracePos.Line != bval.RBracePos.Line { 1056 if s[0] != '\n' { 1057 panic("expected \n") 1058 } 1059 // If B is a multi line list, skip the first "\n" in case A already has a trailing "\n" 1060 s = s[1:] 1061 } 1062 if aval.LBracePos.Line == aval.RBracePos.Line { 1063 // A is a single line list with no trailing comma 1064 if len(aval.Values) > 0 { 1065 s = "," + s 1066 } 1067 } 1068 1069 err := patchlist.Add(aval.RBracePos.Offset, aval.RBracePos.Offset, s) 1070 if err != nil { 1071 return err 1072 } 1073 err = patchlist.Add(b.NamePos.Offset, b.End().Offset+2, "") 1074 if err != nil { 1075 return err 1076 } 1077 1078 return nil 1079} 1080 1081// removes from <items> every item present in <removals> 1082func filterExpressionList(patchList *parser.PatchList, items *parser.List, removals *parser.List) { 1083 writeIndex := 0 1084 for _, item := range items.Values { 1085 included := true 1086 for _, removal := range removals.Values { 1087 equal, err := parser.ExpressionsAreSame(item, removal) 1088 if err != nil { 1089 continue 1090 } 1091 if equal { 1092 included = false 1093 break 1094 } 1095 } 1096 if included { 1097 items.Values[writeIndex] = item 1098 writeIndex++ 1099 } else { 1100 patchList.Add(item.Pos().Offset, item.End().Offset+2, "") 1101 } 1102 } 1103 items.Values = items.Values[:writeIndex] 1104} 1105 1106// Remove each modules[i].Properties[<legacyName>][j] that matches a modules[i].Properties[<canonicalName>][k] 1107func removeMatchingModuleListProperties(mod *parser.Module, patchList *parser.PatchList, canonicalName string, legacyName string) error { 1108 legacyProp, ok := mod.GetProperty(legacyName) 1109 if !ok { 1110 return nil 1111 } 1112 legacyList, ok := legacyProp.Value.(*parser.List) 1113 if !ok || len(legacyList.Values) == 0 { 1114 return nil 1115 } 1116 canonicalList, ok := getLiteralListProperty(mod, canonicalName) 1117 if !ok { 1118 return nil 1119 } 1120 1121 localPatches := parser.PatchList{} 1122 filterExpressionList(&localPatches, legacyList, canonicalList) 1123 1124 if len(legacyList.Values) == 0 { 1125 patchList.Add(legacyProp.Pos().Offset, legacyProp.End().Offset+2, "") 1126 } else { 1127 for _, p := range localPatches { 1128 patchList.Add(p.Start, p.End, p.Replacement) 1129 } 1130 } 1131 1132 return nil 1133} 1134 1135func hasNonEmptyLiteralListProperty(mod *parser.Module, name string) bool { 1136 list, found := getLiteralListProperty(mod, name) 1137 return found && len(list.Values) > 0 1138} 1139 1140func hasNonEmptyLiteralStringProperty(mod *parser.Module, name string) bool { 1141 s, found := getLiteralStringPropertyValue(mod, name) 1142 return found && len(s) > 0 1143} 1144 1145func getLiteralListProperty(mod *parser.Module, name string) (list *parser.List, found bool) { 1146 prop, ok := mod.GetProperty(name) 1147 if !ok { 1148 return nil, false 1149 } 1150 list, ok = prop.Value.(*parser.List) 1151 return list, ok 1152} 1153 1154func getLiteralListPropertyValue(mod *parser.Module, name string) (list []string, found bool) { 1155 listValue, ok := getLiteralListProperty(mod, name) 1156 if !ok { 1157 return nil, false 1158 } 1159 for _, v := range listValue.Values { 1160 stringValue, ok := v.(*parser.String) 1161 if !ok { 1162 return nil, false 1163 } 1164 list = append(list, stringValue.Value) 1165 } 1166 1167 return list, true 1168} 1169 1170func getLiteralStringProperty(mod *parser.Module, name string) (s *parser.String, found bool) { 1171 prop, ok := mod.GetProperty(name) 1172 if !ok { 1173 return nil, false 1174 } 1175 s, ok = prop.Value.(*parser.String) 1176 return s, ok 1177} 1178 1179func getLiteralStringPropertyValue(mod *parser.Module, name string) (s string, found bool) { 1180 stringValue, ok := getLiteralStringProperty(mod, name) 1181 if !ok { 1182 return "", false 1183 } 1184 1185 return stringValue.Value, true 1186} 1187 1188func getLiteralBoolProperty(mod *parser.Module, name string) (b *parser.Bool, found bool) { 1189 prop, ok := mod.GetProperty(name) 1190 if !ok { 1191 return nil, false 1192 } 1193 b, ok = prop.Value.(*parser.Bool) 1194 return b, ok 1195} 1196 1197func getLiteralBoolPropertyValue(mod *parser.Module, name string) (s bool, found bool) { 1198 boolValue, ok := getLiteralBoolProperty(mod, name) 1199 if !ok { 1200 return false, false 1201 } 1202 1203 return boolValue.Value, true 1204} 1205 1206func propertyIndex(props []*parser.Property, propertyName string) int { 1207 for i, prop := range props { 1208 if prop.Name == propertyName { 1209 return i 1210 } 1211 } 1212 return -1 1213} 1214 1215func renameProperty(mod *parser.Module, from, to string) { 1216 for _, prop := range mod.Properties { 1217 if prop.Name == from { 1218 prop.Name = to 1219 } 1220 } 1221} 1222 1223func removeProperty(mod *parser.Module, propertyName string) { 1224 newList := make([]*parser.Property, 0, len(mod.Properties)) 1225 for _, prop := range mod.Properties { 1226 if prop.Name != propertyName { 1227 newList = append(newList, prop) 1228 } 1229 } 1230 mod.Properties = newList 1231} 1232 1233func inList(s string, list []string) bool { 1234 for _, v := range list { 1235 if s == v { 1236 return true 1237 } 1238 } 1239 return false 1240} 1241