diff options
| -rw-r--r-- | android/Android.bp | 2 | ||||
| -rw-r--r-- | android/all_teams.go | 106 | ||||
| -rw-r--r-- | android/all_teams_test.go | 63 | ||||
| -rw-r--r-- | android/config.go | 5 | ||||
| -rw-r--r-- | android/shared_properties.go | 26 | ||||
| -rw-r--r-- | android/team.go | 9 | ||||
| -rw-r--r-- | android/team_proto/team.pb.go | 62 | ||||
| -rw-r--r-- | android/team_proto/team.proto | 10 | ||||
| -rw-r--r-- | android/team_test.go | 25 | ||||
| -rw-r--r-- | cc/cc_test.go | 30 | ||||
| -rw-r--r-- | cc/library.go | 82 | ||||
| -rw-r--r-- | cc/sanitize.go | 1 | ||||
| -rw-r--r-- | cc/testing.go | 1 | ||||
| -rw-r--r-- | filesystem/filesystem.go | 64 | ||||
| -rw-r--r-- | filesystem/filesystem_test.go | 24 | ||||
| -rw-r--r-- | filesystem/system_image.go | 16 |
16 files changed, 407 insertions, 119 deletions
diff --git a/android/Android.bp b/android/Android.bp index bf7804ae5..4c59592c8 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -89,6 +89,7 @@ bootstrap_go_package { "sandbox.go", "sdk.go", "sdk_version.go", + "shared_properties.go", "singleton.go", "singleton_module.go", "soong_config_modules.go", @@ -102,6 +103,7 @@ bootstrap_go_package { "visibility.go", ], testSrcs: [ + "all_teams_test.go", "android_test.go", "androidmk_test.go", "apex_test.go", diff --git a/android/all_teams.go b/android/all_teams.go index b177e20e7..0c433a6cb 100644 --- a/android/all_teams.go +++ b/android/all_teams.go @@ -23,9 +23,18 @@ func registerAllTeamBuildComponents(ctx RegistrationContext) { } // For each module, list the team or the bpFile the module is defined in. -type moduleTeamInfo struct { +type moduleTeamAndTestInfo struct { + // Name field from bp file for the team teamName string - bpFile string + // Blueprint file the module is located in. + bpFile string + // Is this module only used by tests. + testOnly bool + // Is this a directly testable target by running the module directly + // or via tradefed. + topLevelTestTarget bool + // String name indicating the module, like `java_library` for reporting. + kind string } type allTeamsSingleton struct { @@ -37,16 +46,16 @@ type allTeamsSingleton struct { // Map of all team modules we visit during GenerateBuildActions teams map[string]teamProperties // Keeps track of team information or bp file for each module we visit. - teams_for_mods map[string]moduleTeamInfo + teams_for_mods map[string]moduleTeamAndTestInfo } // See if there is a package module for the given bpFilePath with a team defined, if so return the team. // If not ascend up to the parent directory and do the same. -func (this *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) { +func (t *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) { // return the Default_team listed in the package if is there. - if p, ok := this.packages[bpFilePath]; ok { - if t := p.Default_team; t != nil { - return this.teams[*p.Default_team], true + if p, ok := t.packages[bpFilePath]; ok { + if defaultTeam := p.Default_team; defaultTeam != nil { + return t.teams[*defaultTeam], true } } // Strip a directory and go up. @@ -57,72 +66,79 @@ func (this *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamPropert if current == "." { return teamProperties{}, false } - return this.lookupDefaultTeam(filepath.Join(parent, base)) + return t.lookupDefaultTeam(filepath.Join(parent, base)) } -// Create a rule to run a tool to collect all the intermediate files -// which list the team per module into one proto file. -func (this *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) { - this.packages = make(map[string]packageProperties) - this.teams = make(map[string]teamProperties) - this.teams_for_mods = make(map[string]moduleTeamInfo) +// Visit all modules and collect all teams and use WriteFileRuleVerbatim +// to write it out. +func (t *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) { + t.packages = make(map[string]packageProperties) + t.teams = make(map[string]teamProperties) + t.teams_for_mods = make(map[string]moduleTeamAndTestInfo) ctx.VisitAllModules(func(module Module) { bpFile := ctx.BlueprintFile(module) + testModInfo := TestModuleInformation{} + if tmi, ok := SingletonModuleProvider(ctx, module, TestOnlyProviderKey); ok { + testModInfo = tmi + } + // Package Modules and Team Modules are stored in a map so we can look them up by name for // modules without a team. if pack, ok := module.(*packageModule); ok { - // Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in this context. + // Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in t context. pkgKey := bpFile - this.packages[pkgKey] = pack.properties + t.packages[pkgKey] = pack.properties return } if team, ok := module.(*teamModule); ok { - this.teams[team.Name()] = team.properties + t.teams[team.Name()] = team.properties return } - // If a team name is given for a module, store it. - // Otherwise store the bpFile so we can do a package walk later. - if module.base().Team() != "" { - this.teams_for_mods[module.Name()] = moduleTeamInfo{teamName: module.base().Team(), bpFile: bpFile} - } else { - this.teams_for_mods[module.Name()] = moduleTeamInfo{bpFile: bpFile} + entry := moduleTeamAndTestInfo{ + bpFile: bpFile, + testOnly: testModInfo.TestOnly, + topLevelTestTarget: testModInfo.TopLevelTarget, + kind: ctx.ModuleType(module), + teamName: module.base().Team(), } + t.teams_for_mods[module.Name()] = entry + }) // Visit all modules again and lookup the team name in the package or parent package if the team // isn't assignged at the module level. - allTeams := this.lookupTeamForAllModules() + allTeams := t.lookupTeamForAllModules() - this.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile) + t.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile) data, err := proto.Marshal(allTeams) if err != nil { ctx.Errorf("Unable to marshal team data. %s", err) } - WriteFileRuleVerbatim(ctx, this.outputPath, string(data)) - ctx.Phony("all_teams", this.outputPath) + WriteFileRuleVerbatim(ctx, t.outputPath, string(data)) + ctx.Phony("all_teams", t.outputPath) } -func (this *allTeamsSingleton) MakeVars(ctx MakeVarsContext) { - ctx.DistForGoal("all_teams", this.outputPath) +func (t *allTeamsSingleton) MakeVars(ctx MakeVarsContext) { + ctx.DistForGoal("all_teams", t.outputPath) } // Visit every (non-package, non-team) module and write out a proto containing // either the declared team data for that module or the package default team data for that module. -func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams { - teamsProto := make([]*team_proto.Team, len(this.teams_for_mods)) - for i, moduleName := range SortedKeys(this.teams_for_mods) { - m, _ := this.teams_for_mods[moduleName] +func (t *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams { + teamsProto := make([]*team_proto.Team, len(t.teams_for_mods)) + for i, moduleName := range SortedKeys(t.teams_for_mods) { + m, _ := t.teams_for_mods[moduleName] teamName := m.teamName var teamProperties teamProperties found := false if teamName != "" { - teamProperties, found = this.teams[teamName] + teamProperties, found = t.teams[teamName] } else { - teamProperties, found = this.lookupDefaultTeam(m.bpFile) + teamProperties, found = t.lookupDefaultTeam(m.bpFile) } trendy_team_id := "" @@ -130,22 +146,18 @@ func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams { trendy_team_id = *teamProperties.Trendy_team_id } - var files []string teamData := new(team_proto.Team) + *teamData = team_proto.Team{ + TargetName: proto.String(moduleName), + Path: proto.String(m.bpFile), + TestOnly: proto.Bool(m.testOnly), + TopLevelTarget: proto.Bool(m.topLevelTestTarget), + Kind: proto.String(m.kind), + } if trendy_team_id != "" { - *teamData = team_proto.Team{ - TrendyTeamId: proto.String(trendy_team_id), - TargetName: proto.String(moduleName), - Path: proto.String(m.bpFile), - File: files, - } + teamData.TrendyTeamId = proto.String(trendy_team_id) } else { // Clients rely on the TrendyTeamId optional field not being set. - *teamData = team_proto.Team{ - TargetName: proto.String(moduleName), - Path: proto.String(m.bpFile), - File: files, - } } teamsProto[i] = teamData } diff --git a/android/all_teams_test.go b/android/all_teams_test.go index a02b86e06..9c2b38e42 100644 --- a/android/all_teams_test.go +++ b/android/all_teams_test.go @@ -24,9 +24,8 @@ import ( func TestAllTeams(t *testing.T) { t.Parallel() ctx := GroupFixturePreparers( - PrepareForTestWithTeamBuildComponents, + prepareForTestWithTeamAndFakes, FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) }), ).RunTestWithBp(t, ` @@ -51,6 +50,12 @@ func TestAllTeams(t *testing.T) { fake { name: "noteam", + test_only: true, + } + fake { + name: "test-and-team-and-top", + test_only: true, + team: "team2", } `) @@ -59,16 +64,31 @@ func TestAllTeams(t *testing.T) { // map of module name -> trendy team name. actualTeams := make(map[string]*string) + actualTests := []string{} + actualTopLevelTests := []string{} + for _, teamProto := range teams.Teams { actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId + if teamProto.GetTestOnly() { + actualTests = append(actualTests, teamProto.GetTargetName()) + } + if teamProto.GetTopLevelTarget() { + actualTopLevelTests = append(actualTopLevelTests, teamProto.GetTargetName()) + } } expectedTeams := map[string]*string{ - "main_test": proto.String("cool_team"), - "tool": proto.String("22222"), - "noteam": nil, + "main_test": proto.String("cool_team"), + "tool": proto.String("22222"), + "test-and-team-and-top": proto.String("22222"), + "noteam": nil, } + expectedTests := []string{ + "noteam", + "test-and-team-and-top", + } AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) + AssertDeepEquals(t, "test matchup", expectedTests, actualTests) } func getTeamProtoOutput(t *testing.T, ctx *TestResult) *team_proto.AllTeams { @@ -171,10 +191,9 @@ func TestPackageLookup(t *testing.T) { } ` ctx := GroupFixturePreparers( - PrepareForTestWithTeamBuildComponents, + prepareForTestWithTeamAndFakes, PrepareForTestWithPackageModule, FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory) }), FixtureAddTextFile("Android.bp", rootBp), @@ -206,3 +225,33 @@ func TestPackageLookup(t *testing.T) { } AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams) } + +type fakeForTests struct { + ModuleBase + + sourceProperties SourceProperties +} + +func fakeFactory() Module { + module := &fakeForTests{} + module.AddProperties(&module.sourceProperties) + InitAndroidModule(module) + + return module +} + +var prepareForTestWithTeamAndFakes = GroupFixturePreparers( + FixtureRegisterWithContext(RegisterTeamBuildComponents), + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterModuleType("fake", fakeFactory) + }), +) + +func (f *fakeForTests) GenerateAndroidBuildActions(ctx ModuleContext) { + if Bool(f.sourceProperties.Test_only) { + SetProvider(ctx, TestOnlyProviderKey, TestModuleInformation{ + TestOnly: Bool(f.sourceProperties.Test_only), + TopLevelTarget: false, + }) + } +} diff --git a/android/config.go b/android/config.go index 714ce5d5d..11bd81b89 100644 --- a/android/config.go +++ b/android/config.go @@ -1409,6 +1409,11 @@ func (c *config) PrevVendorApiLevel() string { return strconv.Itoa(vendorApiLevel - 100) } +func IsTrunkStableVendorApiLevel(level string) bool { + levelInt, err := strconv.Atoi(level) + return err == nil && levelInt >= 202404 +} + func (c *config) VendorApiLevelFrozen() bool { return c.productVariables.GetBuildFlagBool("RELEASE_BOARD_API_LEVEL_FROZEN") } diff --git a/android/shared_properties.go b/android/shared_properties.go new file mode 100644 index 000000000..84d68fa14 --- /dev/null +++ b/android/shared_properties.go @@ -0,0 +1,26 @@ +// Copyright 2024 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 + +// For storing user-supplied properties about source code on a module to be queried later. +type SourceProperties struct { + // Indicates that the module and its source code are only used in tests, not + // production code. Used by coverage reports and potentially other tools. + Test_only *bool + // Used internally to write if this is a top level test target. + // i.e. something that can be run directly or through tradefed as a test. + // `java_library` would be false, `java_test` would be true. + Top_level_test_target bool `blueprint:"mutated"` +} diff --git a/android/team.go b/android/team.go index df61f4021..c273dc647 100644 --- a/android/team.go +++ b/android/team.go @@ -14,6 +14,8 @@ package android +import "github.com/google/blueprint" + func init() { RegisterTeamBuildComponents(InitRegistrationContext) } @@ -37,6 +39,13 @@ type teamModule struct { properties teamProperties } +type TestModuleInformation struct { + TestOnly bool + TopLevelTarget bool +} + +var TestOnlyProviderKey = blueprint.NewProvider[TestModuleInformation]() + // Real work is done for the module that depends on us. // If needed, the team can serialize the config to json/proto file as well. func (t *teamModule) GenerateAndroidBuildActions(ctx ModuleContext) {} diff --git a/android/team_proto/team.pb.go b/android/team_proto/team.pb.go index 61260cf78..8414d176a 100644 --- a/android/team_proto/team.pb.go +++ b/android/team_proto/team.pb.go @@ -46,6 +46,13 @@ type Team struct { TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"` // OPTIONAL: Files directly owned by this module. File []string `protobuf:"bytes,4,rep,name=file" json:"file,omitempty"` + // OPTIONAL: Is this a test-only module. + TestOnly *bool `protobuf:"varint,5,opt,name=test_only,json=testOnly" json:"test_only,omitempty"` + // OPTIONAL: Is this intended to be run as a test target. + // This target can be run directly as a test or passed to tradefed. + TopLevelTarget *bool `protobuf:"varint,6,opt,name=top_level_target,json=topLevelTarget" json:"top_level_target,omitempty"` + // OPTIONAL: Name of module kind, i.e. java_library + Kind *string `protobuf:"bytes,7,opt,name=kind" json:"kind,omitempty"` } func (x *Team) Reset() { @@ -108,6 +115,27 @@ func (x *Team) GetFile() []string { return nil } +func (x *Team) GetTestOnly() bool { + if x != nil && x.TestOnly != nil { + return *x.TestOnly + } + return false +} + +func (x *Team) GetTopLevelTarget() bool { + if x != nil && x.TopLevelTarget != nil { + return *x.TopLevelTarget + } + return false +} + +func (x *Team) GetKind() string { + if x != nil && x.Kind != nil { + return *x.Kind + } + return "" +} + type AllTeams struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -159,20 +187,26 @@ var File_team_proto protoreflect.FileDescriptor var file_team_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x74, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x74, 0x65, - 0x61, 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x75, 0x0a, 0x04, 0x54, 0x65, 0x61, 0x6d, - 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x5f, - 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, - 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66, - 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x22, - 0x32, 0x0a, 0x08, 0x41, 0x6c, 0x6c, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x05, 0x74, - 0x65, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x65, 0x61, - 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x65, 0x61, 0x6d, 0x52, 0x05, 0x74, 0x65, - 0x61, 0x6d, 0x73, 0x42, 0x22, 0x5a, 0x20, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, - 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x74, 0x65, 0x61, - 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x61, 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd0, 0x01, 0x0a, 0x04, 0x54, 0x65, 0x61, + 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, + 0x5f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, + 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x66, 0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x08, 0x74, 0x65, 0x73, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x28, 0x0a, + 0x10, 0x74, 0x6f, 0x70, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x74, 0x6f, 0x70, 0x4c, 0x65, 0x76, 0x65, + 0x6c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x22, 0x32, 0x0a, 0x08, 0x41, + 0x6c, 0x6c, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x05, 0x74, 0x65, 0x61, 0x6d, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x65, 0x61, 0x6d, 0x52, 0x05, 0x74, 0x65, 0x61, 0x6d, 0x73, 0x42, + 0x22, 0x5a, 0x20, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, + 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x74, 0x65, 0x61, 0x6d, 0x5f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, } var ( diff --git a/android/team_proto/team.proto b/android/team_proto/team.proto index 401eccc6e..69ebf4332 100644 --- a/android/team_proto/team.proto +++ b/android/team_proto/team.proto @@ -27,6 +27,16 @@ message Team { // OPTIONAL: Files directly owned by this module. repeated string file = 4; + + // OPTIONAL: Is this a test-only module. + optional bool test_only = 5; + + // OPTIONAL: Is this intended to be run as a test target. + // This target can be run directly as a test or passed to tradefed. + optional bool top_level_target = 6; + + // OPTIONAL: Name of module kind, i.e. java_library + optional string kind = 7; } message AllTeams { diff --git a/android/team_test.go b/android/team_test.go index 75b3e9fbb..ccfcaaa66 100644 --- a/android/team_test.go +++ b/android/team_test.go @@ -27,16 +27,19 @@ func fakeModuleFactory() Module { return module } +var prepareForTestWithTeamAndFakeBuildComponents = GroupFixturePreparers( + FixtureRegisterWithContext(RegisterTeamBuildComponents), + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterModuleType("fake", fakeModuleFactory) + }), +) + func (*fakeModuleForTests) GenerateAndroidBuildActions(ModuleContext) {} func TestTeam(t *testing.T) { t.Parallel() - ctx := GroupFixturePreparers( - PrepareForTestWithTeamBuildComponents, - FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) - }), - ).RunTestWithBp(t, ` + ctx := prepareForTestWithTeamAndFakeBuildComponents. + RunTestWithBp(t, ` fake { name: "main_test", team: "someteam", @@ -66,12 +69,7 @@ func TestTeam(t *testing.T) { func TestMissingTeamFails(t *testing.T) { t.Parallel() - GroupFixturePreparers( - PrepareForTestWithTeamBuildComponents, - FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) - }), - ). + prepareForTestWithTeamAndFakeBuildComponents. ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern("depends on undefined module \"ring-bearer")). RunTestWithBp(t, ` fake { @@ -86,9 +84,6 @@ func TestPackageBadTeamNameFails(t *testing.T) { GroupFixturePreparers( PrepareForTestWithTeamBuildComponents, PrepareForTestWithPackageModule, - FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.RegisterModuleType("fake", fakeModuleFactory) - }), ). ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern("depends on undefined module \"ring-bearer")). RunTestWithBp(t, ` diff --git a/cc/cc_test.go b/cc/cc_test.go index 74fae04f4..d4955c615 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -998,12 +998,30 @@ func TestLlndkLibrary(t *testing.T) { expectedDirs, f.IncludeDirs) } - checkExportedIncludeDirs("libllndk", "android_arm64_armv8-a_shared", "include") - checkExportedIncludeDirs("libllndk", "android_vendor_arm64_armv8-a_shared", "include") - checkExportedIncludeDirs("libllndk_with_external_headers", "android_arm64_armv8-a_shared", "include") - checkExportedIncludeDirs("libllndk_with_external_headers", "android_vendor_arm64_armv8-a_shared", "include_llndk") - checkExportedIncludeDirs("libllndk_with_override_headers", "android_arm64_armv8-a_shared", "include") - checkExportedIncludeDirs("libllndk_with_override_headers", "android_vendor_arm64_armv8-a_shared", "include_llndk") + checkExportedIncludeDirs("libllndk", coreVariant, "include") + checkExportedIncludeDirs("libllndk", vendorVariant, "include") + checkExportedIncludeDirs("libllndk_with_external_headers", coreVariant, "include") + checkExportedIncludeDirs("libllndk_with_external_headers", vendorVariant, "include_llndk") + checkExportedIncludeDirs("libllndk_with_override_headers", coreVariant, "include") + checkExportedIncludeDirs("libllndk_with_override_headers", vendorVariant, "include_llndk") + + checkAbiLinkerIncludeDirs := func(module string) { + t.Helper() + coreModule := result.ModuleForTests(module, coreVariant) + abiCheckFlags := "" + for _, output := range coreModule.AllOutputs() { + if strings.HasSuffix(output, ".so.llndk.lsdump") { + abiCheckFlags = coreModule.Output(output).Args["exportedHeaderFlags"] + } + } + vendorModule := result.ModuleForTests(module, vendorVariant).Module() + vendorInfo, _ := android.SingletonModuleProvider(result, vendorModule, FlagExporterInfoProvider) + android.AssertStringEquals(t, module+" has different exported include dirs for vendor variant and ABI check", + android.JoinPathsWithPrefix(vendorInfo.IncludeDirs, "-I"), abiCheckFlags) + } + checkAbiLinkerIncludeDirs("libllndk") + checkAbiLinkerIncludeDirs("libllndk_with_override_headers") + checkAbiLinkerIncludeDirs("libllndk_with_external_headers") } func TestLlndkHeaders(t *testing.T) { diff --git a/cc/library.go b/cc/library.go index f3db2ef5e..d9754df99 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1138,7 +1138,7 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...) library.coverageOutputFile = transformCoverageFilesToZip(ctx, objs, library.getLibName(ctx)) - library.linkSAbiDumpFiles(ctx, objs, fileName, unstrippedOutputFile) + library.linkSAbiDumpFiles(ctx, deps, objs, fileName, unstrippedOutputFile) var transitiveStaticLibrariesForOrdering *android.DepSet[android.Path] if static := ctx.GetDirectDepsWithTag(staticVariantTag); len(static) > 0 { @@ -1207,6 +1207,45 @@ func (library *libraryDecorator) exportedIncludeDirsForAbiCheck(ctx ModuleContex return exportIncludeDirs } +func (library *libraryDecorator) llndkIncludeDirsForAbiCheck(ctx ModuleContext, deps PathDeps) []string { + // The ABI checker does not need the preprocess which adds macro guards to function declarations. + includeDirs := android.PathsForModuleSrc(ctx, library.Properties.Llndk.Export_preprocessed_headers).Strings() + + if library.Properties.Llndk.Override_export_include_dirs != nil { + includeDirs = append(includeDirs, android.PathsForModuleSrc( + ctx, library.Properties.Llndk.Override_export_include_dirs).Strings()...) + } else { + includeDirs = append(includeDirs, library.flagExporter.exportedIncludes(ctx).Strings()...) + // Ignore library.sabi.Properties.ReexportedIncludes because + // LLNDK does not reexport the implementation's dependencies, such as export_header_libs. + } + + systemIncludeDirs := []string{} + if Bool(library.Properties.Llndk.Export_headers_as_system) { + systemIncludeDirs = append(systemIncludeDirs, includeDirs...) + includeDirs = nil + } + // Header libs. + includeDirs = append(includeDirs, deps.LlndkIncludeDirs.Strings()...) + systemIncludeDirs = append(systemIncludeDirs, deps.LlndkSystemIncludeDirs.Strings()...) + // The ABI checker does not distinguish normal and system headers. + return append(includeDirs, systemIncludeDirs...) +} + +func (library *libraryDecorator) linkLlndkSAbiDumpFiles(ctx ModuleContext, + deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string, + excludeSymbolVersions, excludeSymbolTags []string) android.Path { + // NDK symbols in version 34 are LLNDK symbols. Those in version 35 are not. + // TODO(b/314010764): Add parameters to read LLNDK symbols from the symbol file. + return transformDumpToLinkedDump(ctx, + sAbiDumpFiles, soFile, libFileName+".llndk", + library.llndkIncludeDirsForAbiCheck(ctx, deps), + android.OptionalPathForModuleSrc(ctx, library.Properties.Llndk.Symbol_file), + append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...), + append([]string{"platform-only"}, excludeSymbolTags...), + "34") +} + func getRefAbiDumpFile(ctx android.ModuleInstallPathContext, versionedDumpDir, fileName string) android.OptionalPath { @@ -1317,13 +1356,15 @@ func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, false /* isLlndkOrNdk */, false /* allowExtensions */, "current", errorMessage) } -func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) { +func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, objs Objects, fileName string, soFile android.Path) { if library.sabi.shouldCreateSourceAbiDump() { exportedIncludeDirs := library.exportedIncludeDirsForAbiCheck(ctx) headerAbiChecker := library.getHeaderAbiCheckerProperties(ctx) currSdkVersion := currRefAbiDumpSdkVersion(ctx) currVendorVersion := ctx.Config().VendorApiLevel() - sourceDump := transformDumpToLinkedDump(ctx, + + // Generate source dumps. + implDump := transformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedIncludeDirs, android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)), @@ -1331,8 +1372,25 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objec headerAbiChecker.Exclude_symbol_tags, currSdkVersion) - for _, tag := range classifySourceAbiDump(ctx) { - addLsdumpPath(string(tag) + ":" + sourceDump.String()) + var llndkDump android.Path + tags := classifySourceAbiDump(ctx) + for _, tag := range tags { + if tag == llndkLsdumpTag { + if llndkDump == nil { + // TODO(b/323447559): Evaluate if replacing sAbiDumpFiles with implDump is faster + llndkDump = library.linkLlndkSAbiDumpFiles(ctx, + deps, objs.sAbiDumpFiles, soFile, fileName, + headerAbiChecker.Exclude_symbol_versions, + headerAbiChecker.Exclude_symbol_tags) + } + addLsdumpPath(string(tag) + ":" + llndkDump.String()) + } else { + addLsdumpPath(string(tag) + ":" + implDump.String()) + } + } + + // Diff source dumps and reference dumps. + for _, tag := range tags { dumpDirName := tag.dirName() if dumpDirName == "" { continue @@ -1347,10 +1405,15 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objec } // Check against the previous version. var prevVersion, currVersion string + sourceDump := implDump // If this release config does not define VendorApiLevel, fall back to the old policy. if isLlndk && currVendorVersion != "" { prevVersion = ctx.Config().PrevVendorApiLevel() currVersion = currVendorVersion + // LLNDK dumps are generated by different rules after trunk stable. + if android.IsTrunkStableVendorApiLevel(prevVersion) { + sourceDump = llndkDump + } } else { prevVersion, currVersion = crossVersionAbiDiffSdkVersions(ctx, dumpDir) } @@ -1361,8 +1424,12 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objec fileName, isLlndk || isNdk, currVersion, nameExt+prevVersion) } // Check against the current version. + sourceDump = implDump if isLlndk && currVendorVersion != "" { currVersion = currVendorVersion + if android.IsTrunkStableVendorApiLevel(currVersion) { + sourceDump = llndkDump + } } else { currVersion = currSdkVersion } @@ -1383,7 +1450,7 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objec continue } library.optInAbiDiff(ctx, - sourceDump, optInDumpFile.Path(), + implDump, optInDumpFile.Path(), fileName, "opt"+strconv.Itoa(i), optInDumpDirPath.String()) } } @@ -1750,9 +1817,6 @@ func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *strin if props := library.getHeaderAbiCheckerProperties(ctx); props.Symbol_file != nil { return props.Symbol_file } - if ctx.Module().(*Module).IsLlndk() { - return library.Properties.Llndk.Symbol_file - } if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil { return library.Properties.Stubs.Symbol_file } diff --git a/cc/sanitize.go b/cc/sanitize.go index 37b3e8521..db046ec58 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -858,6 +858,7 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { flags.Local.CFlags = append(flags.Local.CFlags, cfiCflags...) flags.Local.AsFlags = append(flags.Local.AsFlags, cfiAsflags...) + flags.CFlagsDeps = append(flags.CFlagsDeps, android.PathForSource(ctx, cfiBlocklistPath + "/" + cfiBlocklistFilename)) if Bool(s.Properties.Sanitize.Config.Cfi_assembly_support) { flags.Local.CFlags = append(flags.Local.CFlags, cfiAssemblySupportFlag) } diff --git a/cc/testing.go b/cc/testing.go index 2aecd5f51..20c435aca 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -580,6 +580,7 @@ var PrepareForTestWithCcDefaultModules = android.GroupFixturePreparers( "defaults/cc/common/crtend_so.c": nil, "defaults/cc/common/crtend.c": nil, "defaults/cc/common/crtbrand.c": nil, + "external/compiler-rt/lib/cfi/cfi_blocklist.txt": nil, "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm64.a": nil, "defaults/cc/common/libclang_rt.ubsan_minimal.android_arm.a": nil, diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index 61127bf16..cadf9c246 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -36,8 +36,8 @@ func init() { func registerBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_filesystem", filesystemFactory) + ctx.RegisterModuleType("android_filesystem_defaults", filesystemDefaultsFactory) ctx.RegisterModuleType("android_system_image", systemImageFactory) - ctx.RegisterModuleType("android_system_image_defaults", systemImageDefaultsFactory) ctx.RegisterModuleType("avb_add_hash_footer", avbAddHashFooterFactory) ctx.RegisterModuleType("avb_add_hash_footer_defaults", avbAddHashFooterDefaultsFactory) ctx.RegisterModuleType("avb_gen_vbmeta_image", avbGenVbmetaImageFactory) @@ -47,6 +47,7 @@ func registerBuildComponents(ctx android.RegistrationContext) { type filesystem struct { android.ModuleBase android.PackagingBase + android.DefaultableModuleBase properties filesystemProperties @@ -144,6 +145,7 @@ func initFilesystemModule(module *filesystem) { module.AddProperties(&module.properties) android.InitPackageModule(module) android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) } var dependencyTag = struct { @@ -190,9 +192,7 @@ func (f *filesystem) partitionName() string { var pctx = android.NewPackageContext("android/soong/filesystem") func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { - if !android.InList(f.PartitionType(), validPartitions) { - ctx.PropertyErrorf("partition_type", "partition_type must be one of %s, found: %s", validPartitions, f.PartitionType()) - } + validatePartitionType(ctx, f) switch f.fsType(ctx) { case ext4Type: f.output = f.buildImageUsingBuildImage(ctx) @@ -208,6 +208,22 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.InstallFile(f.installDir, f.installFileName(), f.output) } +func validatePartitionType(ctx android.ModuleContext, p partition) { + if !android.InList(p.PartitionType(), validPartitions) { + ctx.PropertyErrorf("partition_type", "partition_type must be one of %s, found: %s", validPartitions, p.PartitionType()) + } + + ctx.VisitDirectDepsWithTag(android.DefaultsDepTag, func(m android.Module) { + if fdm, ok := m.(*filesystemDefaults); ok { + if p.PartitionType() != fdm.PartitionType() { + ctx.PropertyErrorf("partition_type", + "%s doesn't match with the partition type %s of the filesystem default module %s", + p.PartitionType(), fdm.PartitionType(), m.Name()) + } + } + }) +} + // Copy extra files/dirs that are not from the `deps` property to `rootDir`, checking for conflicts with files // already in `rootDir`. func (f *filesystem) buildNonDepsFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.OutputPath) { @@ -469,10 +485,16 @@ func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *andro Text(android.PathForArbitraryOutput(ctx, stagingDir).String()) } +type partition interface { + PartitionType() string +} + func (f *filesystem) PartitionType() string { return proptools.StringDefault(f.properties.Partition_type, "system") } +var _ partition = (*filesystem)(nil) + var _ android.AndroidMkEntriesProvider = (*filesystem)(nil) // Implements android.AndroidMkEntriesProvider @@ -546,3 +568,37 @@ var _ cc.UseCoverage = (*filesystem)(nil) func (*filesystem) IsNativeCoverageNeeded(ctx android.IncomingTransitionContext) bool { return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled() } + +// android_filesystem_defaults + +type filesystemDefaults struct { + android.ModuleBase + android.DefaultsModuleBase + + properties filesystemDefaultsProperties +} + +type filesystemDefaultsProperties struct { + // Identifies which partition this is for //visibility:any_system_image (and others) visibility + // checks, and will be used in the future for API surface checks. + Partition_type *string +} + +// android_filesystem_defaults is a default module for android_filesystem and android_system_image +func filesystemDefaultsFactory() android.Module { + module := &filesystemDefaults{} + module.AddProperties(&module.properties) + module.AddProperties(&android.PackagingProperties{}) + android.InitDefaultsModule(module) + return module +} + +func (f *filesystemDefaults) PartitionType() string { + return proptools.StringDefault(f.properties.Partition_type, "system") +} + +var _ partition = (*filesystemDefaults)(nil) + +func (f *filesystemDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { + validatePartitionType(ctx, f) +} diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go index 3ce5d4e88..f4ecad46c 100644 --- a/filesystem/filesystem_test.go +++ b/filesystem/filesystem_test.go @@ -381,7 +381,7 @@ func TestFileSystemWithCoverageVariants(t *testing.T) { func TestSystemImageDefaults(t *testing.T) { result := fixture.RunTestWithBp(t, ` - android_system_image_defaults { + android_filesystem_defaults { name: "defaults", multilib: { common: { @@ -447,3 +447,25 @@ func TestSystemImageDefaults(t *testing.T) { android.AssertStringListContains(t, "missing entry", fs.entries, e) } } + +func TestInconsistentPartitionTypesInDefaults(t *testing.T) { + fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern( + "doesn't match with the partition type")). + RunTestWithBp(t, ` + android_filesystem_defaults { + name: "system_ext_def", + partition_type: "system_ext", + } + + android_filesystem_defaults { + name: "system_def", + partition_type: "system", + defaults: ["system_ext_def"], + } + + android_system_image { + name: "system", + defaults: ["system_def"], + } + `) +} diff --git a/filesystem/system_image.go b/filesystem/system_image.go index 92bb206bc..5028a493e 100644 --- a/filesystem/system_image.go +++ b/filesystem/system_image.go @@ -21,7 +21,6 @@ import ( type systemImage struct { filesystem - android.DefaultableModuleBase properties systemImageProperties } @@ -40,7 +39,6 @@ func systemImageFactory() android.Module { module.filesystem.buildExtraFiles = module.buildExtraFiles module.filesystem.filterPackagingSpec = module.filterPackagingSpec initFilesystemModule(&module.filesystem) - android.InitDefaultableModule(module) return module } @@ -102,17 +100,3 @@ func (s *systemImage) buildLinkerConfigFile(ctx android.ModuleContext, root andr func (s *systemImage) filterPackagingSpec(ps android.PackagingSpec) bool { return ps.Partition() == "system" } - -type systemImageDefaults struct { - android.ModuleBase - android.DefaultsModuleBase -} - -// android_system_image_defaults is a default module for android_system_image module. -func systemImageDefaultsFactory() android.Module { - module := &systemImageDefaults{} - module.AddProperties(&android.PackagingProperties{}) - module.AddProperties(&systemImageProperties{}) - android.InitDefaultsModule(module) - return module -} |