diff --git a/android/Android.bp b/android/Android.bp index 487372bd8..c196b7a3e 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -23,6 +23,7 @@ bootstrap_go_package { "filegroup.go", "hooks.go", "image.go", + "makefile_goal.go", "makevars.go", "metrics.go", "module.go", diff --git a/android/makefile_goal.go b/android/makefile_goal.go new file mode 100644 index 000000000..eae3976a8 --- /dev/null +++ b/android/makefile_goal.go @@ -0,0 +1,99 @@ +// Copyright 2020 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 ( + "fmt" + "io" + "path/filepath" + + "github.com/google/blueprint/proptools" +) + +func init() { + RegisterModuleType("makefile_goal", MakefileGoalFactory) +} + +type makefileGoalProperties struct { + // Sources. + + // Makefile goal output file path, relative to PRODUCT_OUT. + Product_out_path *string +} + +type makefileGoal struct { + ModuleBase + + properties makefileGoalProperties + + // Destination. Output file path of this module. + outputFilePath OutputPath +} + +var _ AndroidMkEntriesProvider = (*makefileGoal)(nil) +var _ OutputFileProducer = (*makefileGoal)(nil) + +// Input file of this makefile_goal module. Nil if none specified. May use variable names in makefiles. +func (p *makefileGoal) inputPath() *string { + if p.properties.Product_out_path != nil { + return proptools.StringPtr(filepath.Join("$(PRODUCT_OUT)", proptools.String(p.properties.Product_out_path))) + } + return nil +} + +// OutputFileProducer +func (p *makefileGoal) OutputFiles(tag string) (Paths, error) { + if tag != "" { + return nil, fmt.Errorf("unsupported tag %q", tag) + } + return Paths{p.outputFilePath}, nil +} + +// AndroidMkEntriesProvider +func (p *makefileGoal) DepsMutator(ctx BottomUpMutatorContext) { + if p.inputPath() == nil { + ctx.PropertyErrorf("product_out_path", "Path relative to PRODUCT_OUT required") + } +} + +func (p *makefileGoal) GenerateAndroidBuildActions(ctx ModuleContext) { + filename := filepath.Base(proptools.String(p.inputPath())) + p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath + + ctx.InstallFile(PathForModuleInstall(ctx, "etc"), ctx.ModuleName(), p.outputFilePath) +} + +func (p *makefileGoal) AndroidMkEntries() []AndroidMkEntries { + return []AndroidMkEntries{AndroidMkEntries{ + Class: "ETC", + OutputFile: OptionalPathForPath(p.outputFilePath), + ExtraFooters: []AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries) { + // Can't use Cp because inputPath() is not a valid Path. + fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath) + }, + }, + }} +} + +// Import a Makefile goal to Soong by copying the file built by +// the goal to a path visible to Soong. This rule only works on boot images. +func MakefileGoalFactory() Module { + module := &makefileGoal{} + module.AddProperties(&module.properties) + // This module is device-only + InitAndroidArchModule(module, DeviceSupported, MultilibFirst) + return module +} diff --git a/android/neverallow.go b/android/neverallow.go index 526d39949..73829f137 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -56,6 +56,7 @@ func init() { AddNeverAllowRules(createJavaDeviceForHostRules()...) AddNeverAllowRules(createCcSdkVariantRules()...) AddNeverAllowRules(createUncompressDexRules()...) + AddNeverAllowRules(createMakefileGoalRules()...) } // Add a NeverAllow rule to the set of rules to apply. @@ -231,6 +232,15 @@ func createUncompressDexRules() []Rule { } } +func createMakefileGoalRules() []Rule { + return []Rule{ + NeverAllow(). + ModuleType("makefile_goal"). + WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")). + Because("Only boot images may be imported as a makefile goal."), + } +} + func neverallowMutator(ctx BottomUpMutatorContext) { m, ok := ctx.Module().(Module) if !ok { diff --git a/android/neverallow_test.go b/android/neverallow_test.go index 45d36a69b..56a07dc9d 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -326,6 +326,20 @@ var neverallowTests = []struct { "module \"outside_art_libraries\": violates neverallow", }, }, + { + name: "disallowed makefile_goal", + fs: map[string][]byte{ + "Android.bp": []byte(` + makefile_goal { + name: "foo", + product_out_path: "boot/trap.img" + } + `), + }, + expectedErrors: []string{ + "Only boot images may be imported as a makefile goal.", + }, + }, } func TestNeverallow(t *testing.T) { @@ -350,6 +364,7 @@ func testNeverallow(config Config) (*TestContext, []error) { ctx.RegisterModuleType("java_library", newMockJavaLibraryModule) ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule) ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule) + ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule) ctx.PostDepsMutators(RegisterNeverallowMutator) ctx.Register(config) @@ -438,3 +453,22 @@ func newMockJavaLibraryModule() Module { func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) { } + +type mockMakefileGoalProperties struct { + Product_out_path *string +} + +type mockMakefileGoalModule struct { + ModuleBase + properties mockMakefileGoalProperties +} + +func newMockMakefileGoalModule() Module { + m := &mockMakefileGoalModule{} + m.AddProperties(&m.properties) + InitAndroidModule(m) + return m +} + +func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) { +}