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