| // Copyright 2022 Google Inc. All rights reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package android | 
 |  | 
 | import ( | 
 | 	"encoding/json" | 
 | 	"os" | 
 | 	"strings" | 
 |  | 
 | 	"github.com/google/blueprint" | 
 | ) | 
 |  | 
 | func init() { | 
 | 	RegisterPluginSingletonBuildComponents(InitRegistrationContext) | 
 | } | 
 |  | 
 | func RegisterPluginSingletonBuildComponents(ctx RegistrationContext) { | 
 | 	ctx.RegisterParallelSingletonType("plugins", pluginSingletonFactory) | 
 | } | 
 |  | 
 | // pluginSingleton is a singleton to handle allowlisting of the final Android-<product_name>.mk file | 
 | // output. | 
 | func pluginSingletonFactory() Singleton { | 
 | 	return &pluginSingleton{} | 
 | } | 
 |  | 
 | type pluginSingleton struct{} | 
 |  | 
 | var allowedPluginsByName = map[string]bool{ | 
 | 	"aidl-soong-rules":                       true, | 
 | 	"arm_compute_library_nn_driver":          true, | 
 | 	"cuttlefish-soong-rules":                 true, | 
 | 	"gki-soong-rules":                        true, | 
 | 	"hidl-soong-rules":                       true, | 
 | 	"kernel-config-soong-rules":              true, | 
 | 	"soong-angle-codegen":                    true, | 
 | 	"soong-api":                              true, | 
 | 	"soong-art":                              true, | 
 | 	"soong-ca-certificates":                  true, | 
 | 	"soong-ca-certificates-apex":             true, | 
 | 	"soong-clang":                            true, | 
 | 	"soong-clang-prebuilts":                  true, | 
 | 	"soong-csuite":                           true, | 
 | 	"soong-fluoride":                         true, | 
 | 	"soong-fs_config":                        true, | 
 | 	"soong-icu":                              true, | 
 | 	"soong-java-config-error_prone":          true, | 
 | 	"soong-libchrome":                        true, | 
 | 	"soong-llvm":                             true, | 
 | 	"soong-robolectric":                      true, | 
 | 	"soong-rust-prebuilts":                   true, | 
 | 	"soong-selinux":                          true, | 
 | 	"soong-wayland-protocol-codegen":         true, | 
 | 	"treble_report_app":                      true, | 
 | 	"treble_report_local":                    true, | 
 | 	"treble_report_module":                   true, | 
 | 	"vintf-compatibility-matrix-soong-rules": true, | 
 | 	"xsdc-soong-rules":                       true, | 
 | } | 
 |  | 
 | var internalPluginsPaths = []string{ | 
 | 	"vendor/google/build/soong/internal_plugins.json", | 
 | } | 
 |  | 
 | type pluginProvider interface { | 
 | 	IsPluginFor(string) bool | 
 | } | 
 |  | 
 | func maybeAddInternalPluginsToAllowlist(ctx SingletonContext) { | 
 | 	for _, internalPluginsPath := range internalPluginsPaths { | 
 | 		if path := ExistentPathForSource(ctx, internalPluginsPath); path.Valid() { | 
 | 			ctx.AddNinjaFileDeps(path.String()) | 
 | 			absPath := absolutePath(path.String()) | 
 | 			var moreAllowed map[string]bool | 
 | 			data, err := os.ReadFile(absPath) | 
 | 			if err != nil { | 
 | 				ctx.Errorf("Failed to open internal plugins path %q %q", internalPluginsPath, err) | 
 | 			} | 
 | 			if err := json.Unmarshal(data, &moreAllowed); err != nil { | 
 | 				ctx.Errorf("Internal plugins file %q did not parse correctly: %q", data, err) | 
 | 			} | 
 | 			for k, v := range moreAllowed { | 
 | 				allowedPluginsByName[k] = v | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func (p *pluginSingleton) GenerateBuildActions(ctx SingletonContext) { | 
 | 	for _, p := range ctx.DeviceConfig().BuildBrokenPluginValidation() { | 
 | 		allowedPluginsByName[p] = true | 
 | 	} | 
 | 	maybeAddInternalPluginsToAllowlist(ctx) | 
 |  | 
 | 	disallowedPlugins := map[string]bool{} | 
 | 	ctx.VisitAllModulesBlueprint(func(module blueprint.Module) { | 
 | 		if ctx.ModuleType(module) != "bootstrap_go_package" { | 
 | 			return | 
 | 		} | 
 |  | 
 | 		p, ok := module.(pluginProvider) | 
 | 		if !ok || !p.IsPluginFor("soong_build") { | 
 | 			return | 
 | 		} | 
 |  | 
 | 		name := ctx.ModuleName(module) | 
 | 		if _, ok := allowedPluginsByName[name]; ok { | 
 | 			return | 
 | 		} | 
 |  | 
 | 		dir := ctx.ModuleDir(module) | 
 |  | 
 | 		// allow use of plugins within Soong to not allowlist everything | 
 | 		if strings.HasPrefix(dir, "build/soong") { | 
 | 			return | 
 | 		} | 
 |  | 
 | 		// allow third party users outside of external to create new plugins, i.e. non-google paths | 
 | 		// under vendor or hardware | 
 | 		if !strings.HasPrefix(dir, "external/") && IsThirdPartyPath(dir) { | 
 | 			return | 
 | 		} | 
 | 		disallowedPlugins[name] = true | 
 | 	}) | 
 | 	if len(disallowedPlugins) > 0 { | 
 | 		ctx.Errorf("New plugins are not supported; however %q were found. Please reach out to the build team or use BUILD_BROKEN_PLUGIN_VALIDATION (see Changes.md for more info).", SortedStringKeys(disallowedPlugins)) | 
 | 	} | 
 | } |