diff options
138 files changed, 5346 insertions, 1487 deletions
diff --git a/android/apex.go b/android/apex.go index 100beb012..f857ec692 100644 --- a/android/apex.go +++ b/android/apex.go @@ -34,6 +34,17 @@ type ApexInfo struct { MinSdkVersion int Updatable bool + RequiredSdks SdkRefs + + InApexes []string +} + +func (i ApexInfo) mergedName() string { + name := "apex" + strconv.Itoa(i.MinSdkVersion) + for _, sdk := range i.RequiredSdks { + name += "_" + sdk.Name + "_" + sdk.Version + } + return name } // Extracted from ApexModule to make it easier to define custom subsets of the @@ -69,17 +80,20 @@ type ApexModule interface { // Call this before apex.apexMutator is run. BuildForApex(apex ApexInfo) - // Returns the APEXes that this module will be built for - ApexVariations() []ApexInfo - // Returns the name of APEX variation that this module will be built for. - //Empty string is returned when 'IsForPlatform() == true'. Note that a - // module can be included in multiple APEXes, in which case, the module - // is mutated into multiple modules each of which for an APEX. This method - // returns the name of the APEX that a variant module is for. + // Empty string is returned when 'IsForPlatform() == true'. Note that a + // module can beincluded in multiple APEXes, in which case, the module + // is mutated into one or more variants, each of which is for one or + // more APEXes. This method returns the name of the APEX variation of + // the module. // Call this after apex.apexMutator is run. ApexVariationName() string + // Returns the name of the APEX modules that this variant of this module + // is present in. + // Call this after apex.apexMutator is run. + InApexes() []string + // Tests whether this module will be built for the platform or not. // This is a shortcut for ApexVariationName() == "" IsForPlatform() bool @@ -128,6 +142,15 @@ type ApexModule interface { // Returns nil if this module supports sdkVersion // Otherwise, returns error with reason ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion int) error + + // Returns true if this module needs a unique variation per apex, for example if + // use_apex_name_macro is set. + UniqueApexVariations() bool + + // UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies + // that are in the same APEX have unique APEX variations so that the module can link against + // the right variant. + UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext) } type ApexProperties struct { @@ -144,6 +167,8 @@ type ApexProperties struct { Info ApexInfo `blueprint:"mutated"` NotAvailableForPlatform bool `blueprint:"mutated"` + + UniqueApexVariationsForDeps bool `blueprint:"mutated"` } // Marker interface that identifies dependencies that are excluded from APEX @@ -179,6 +204,47 @@ func (m *ApexModuleBase) TestFor() []string { return nil } +func (m *ApexModuleBase) UniqueApexVariations() bool { + return false +} + +func (m *ApexModuleBase) UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext) { + // anyInSameApex returns true if the two ApexInfo lists contain any values in an InApexes list + // in common. It is used instead of DepIsInSameApex because it needs to determine if the dep + // is in the same APEX due to being directly included, not only if it is included _because_ it + // is a dependency. + anyInSameApex := func(a, b []ApexInfo) bool { + collectApexes := func(infos []ApexInfo) []string { + var ret []string + for _, info := range infos { + ret = append(ret, info.InApexes...) + } + return ret + } + + aApexes := collectApexes(a) + bApexes := collectApexes(b) + sort.Strings(bApexes) + for _, aApex := range aApexes { + index := sort.SearchStrings(bApexes, aApex) + if index < len(bApexes) && bApexes[index] == aApex { + return true + } + } + return false + } + + mctx.VisitDirectDeps(func(dep Module) { + if depApexModule, ok := dep.(ApexModule); ok { + if anyInSameApex(depApexModule.apexModuleBase().apexVariations, m.apexVariations) && + (depApexModule.UniqueApexVariations() || + depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) { + m.ApexProperties.UniqueApexVariationsForDeps = true + } + } + }) +} + func (m *ApexModuleBase) BuildForApex(apex ApexInfo) { m.apexVariationsLock.Lock() defer m.apexVariationsLock.Unlock() @@ -190,14 +256,14 @@ func (m *ApexModuleBase) BuildForApex(apex ApexInfo) { m.apexVariations = append(m.apexVariations, apex) } -func (m *ApexModuleBase) ApexVariations() []ApexInfo { - return m.apexVariations -} - func (m *ApexModuleBase) ApexVariationName() string { return m.ApexProperties.Info.ApexVariationName } +func (m *ApexModuleBase) InApexes() []string { + return m.ApexProperties.Info.InApexes +} + func (m *ApexModuleBase) IsForPlatform() bool { return m.ApexProperties.Info.ApexVariationName == "" } @@ -278,14 +344,45 @@ func (a byApexName) Len() int { return len(a) } func (a byApexName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a byApexName) Less(i, j int) bool { return a[i].ApexVariationName < a[j].ApexVariationName } +// mergeApexVariations deduplicates APEX variations that would build identically into a common +// variation. It returns the reduced list of variations and a list of aliases from the original +// variation names to the new variation names. +func mergeApexVariations(apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) { + sort.Sort(byApexName(apexVariations)) + seen := make(map[string]int) + for _, apexInfo := range apexVariations { + apexName := apexInfo.ApexVariationName + mergedName := apexInfo.mergedName() + if index, exists := seen[mergedName]; exists { + merged[index].InApexes = append(merged[index].InApexes, apexName) + merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable + } else { + seen[mergedName] = len(merged) + apexInfo.ApexVariationName = apexInfo.mergedName() + apexInfo.InApexes = CopyOf(apexInfo.InApexes) + merged = append(merged, apexInfo) + } + aliases = append(aliases, [2]string{apexName, mergedName}) + } + return merged, aliases +} + func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module { if len(m.apexVariations) > 0 { m.checkApexAvailableProperty(mctx) - sort.Sort(byApexName(m.apexVariations)) + var apexVariations []ApexInfo + var aliases [][2]string + if !mctx.Module().(ApexModule).UniqueApexVariations() && !m.ApexProperties.UniqueApexVariationsForDeps { + apexVariations, aliases = mergeApexVariations(m.apexVariations) + } else { + apexVariations = m.apexVariations + } + + sort.Sort(byApexName(apexVariations)) variations := []string{} variations = append(variations, "") // Original variation for platform - for _, apex := range m.apexVariations { + for _, apex := range apexVariations { variations = append(variations, apex.ApexVariationName) } @@ -302,9 +399,14 @@ func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Mod mod.MakeUninstallable() } if !platformVariation { - mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1] + mod.(ApexModule).apexModuleBase().ApexProperties.Info = apexVariations[i-1] } } + + for _, alias := range aliases { + mctx.CreateAliasVariation(alias[0], alias[1]) + } + return modules } return nil @@ -339,6 +441,9 @@ func UpdateApexDependency(apex ApexInfo, moduleName string, directDep bool) { apexNamesMap()[moduleName] = apexesForModule } apexesForModule[apex.ApexVariationName] = apexesForModule[apex.ApexVariationName] || directDep + for _, apexName := range apex.InApexes { + apexesForModule[apexName] = apexesForModule[apex.ApexVariationName] || directDep + } } // TODO(b/146393795): remove this when b/146393795 is fixed @@ -354,12 +459,26 @@ func ClearApexDependency() { func DirectlyInApex(apexName string, moduleName string) bool { apexNamesMapMutex.Lock() defer apexNamesMapMutex.Unlock() - if apexNames, ok := apexNamesMap()[moduleName]; ok { - return apexNames[apexName] + if apexNamesForModule, ok := apexNamesMap()[moduleName]; ok { + return apexNamesForModule[apexName] } return false } +// Tests whether a module named moduleName is directly depended on by all APEXes +// in a list of apexNames. +func DirectlyInAllApexes(apexNames []string, moduleName string) bool { + apexNamesMapMutex.Lock() + defer apexNamesMapMutex.Unlock() + for _, apexName := range apexNames { + apexNamesForModule := apexNamesMap()[moduleName] + if !apexNamesForModule[apexName] { + return false + } + } + return true +} + type hostContext interface { Host() bool } diff --git a/android/apex_test.go b/android/apex_test.go new file mode 100644 index 000000000..db02833e7 --- /dev/null +++ b/android/apex_test.go @@ -0,0 +1,111 @@ +// 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 ( + "reflect" + "testing" +) + +func Test_mergeApexVariations(t *testing.T) { + tests := []struct { + name string + in []ApexInfo + wantMerged []ApexInfo + wantAliases [][2]string + }{ + { + name: "single", + in: []ApexInfo{ + {"foo", 10000, false, nil, []string{"foo"}}, + }, + wantMerged: []ApexInfo{ + {"apex10000", 10000, false, nil, []string{"foo"}}, + }, + wantAliases: [][2]string{ + {"foo", "apex10000"}, + }, + }, + { + name: "merge", + in: []ApexInfo{ + {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}}, + {"bar", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar"}}, + }, + wantMerged: []ApexInfo{ + {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}}, + }, + wantAliases: [][2]string{ + {"bar", "apex10000_baz_1"}, + {"foo", "apex10000_baz_1"}, + }, + }, + { + name: "don't merge version", + in: []ApexInfo{ + {"foo", 10000, false, nil, []string{"foo"}}, + {"bar", 30, false, nil, []string{"bar"}}, + }, + wantMerged: []ApexInfo{ + {"apex30", 30, false, nil, []string{"bar"}}, + {"apex10000", 10000, false, nil, []string{"foo"}}, + }, + wantAliases: [][2]string{ + {"bar", "apex30"}, + {"foo", "apex10000"}, + }, + }, + { + name: "merge updatable", + in: []ApexInfo{ + {"foo", 10000, false, nil, []string{"foo"}}, + {"bar", 10000, true, nil, []string{"bar"}}, + }, + wantMerged: []ApexInfo{ + {"apex10000", 10000, true, nil, []string{"bar", "foo"}}, + }, + wantAliases: [][2]string{ + {"bar", "apex10000"}, + {"foo", "apex10000"}, + }, + }, + { + name: "don't merge sdks", + in: []ApexInfo{ + {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}}, + {"bar", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}}, + }, + wantMerged: []ApexInfo{ + {"apex10000_baz_2", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}}, + {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}}, + }, + wantAliases: [][2]string{ + {"bar", "apex10000_baz_2"}, + {"foo", "apex10000_baz_1"}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotMerged, gotAliases := mergeApexVariations(tt.in) + if !reflect.DeepEqual(gotMerged, tt.wantMerged) { + t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged) + } + if !reflect.DeepEqual(gotAliases, tt.wantAliases) { + t.Errorf("mergeApexVariations() gotAliases = %v, want %v", gotAliases, tt.wantAliases) + } + }) + } +} diff --git a/android/api_levels.go b/android/api_levels.go index b6296d815..087206633 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -73,6 +73,7 @@ func getApiLevelsMap(config Config) map[string]int { "O-MR1": 27, "P": 28, "Q": 29, + "R": 30, } for i, codename := range config.PlatformVersionActiveCodenames() { apiLevelsMap[codename] = baseApiLevel + i diff --git a/android/arch.go b/android/arch.go index a99915f39..8500bc7ec 100644 --- a/android/arch.go +++ b/android/arch.go @@ -23,6 +23,7 @@ import ( "strings" "github.com/google/blueprint" + "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/proptools" ) @@ -551,6 +552,15 @@ var BuildOs = func() OsType { } }() +var BuildArch = func() ArchType { + switch runtime.GOARCH { + case "amd64": + return X86_64 + default: + panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH)) + } +}() + var ( OsTypeList []OsType commonTargetMap = make(map[string]Target) @@ -569,7 +579,7 @@ var ( osArchTypeMap = map[OsType][]ArchType{ Linux: []ArchType{X86, X86_64}, - LinuxBionic: []ArchType{X86_64}, + LinuxBionic: []ArchType{Arm64, X86_64}, Darwin: []ArchType{X86_64}, Windows: []ArchType{X86, X86_64}, Android: []ArchType{Arm, Arm64, X86, X86_64}, @@ -689,13 +699,31 @@ func (target Target) Variations() []blueprint.Variation { } } -func osMutator(mctx BottomUpMutatorContext) { +func osMutator(bpctx blueprint.BottomUpMutatorContext) { var module Module var ok bool - if module, ok = mctx.Module().(Module); !ok { + if module, ok = bpctx.Module().(Module); !ok { + if bootstrap.IsBootstrapModule(bpctx.Module()) { + // Bootstrap Go modules are always the build OS or linux bionic. + config := bpctx.Config().(Config) + osNames := []string{config.BuildOSTarget.OsVariation()} + for _, hostCrossTarget := range config.Targets[LinuxBionic] { + if hostCrossTarget.Arch.ArchType == config.BuildOSTarget.Arch.ArchType { + osNames = append(osNames, hostCrossTarget.OsVariation()) + } + } + osNames = FirstUniqueStrings(osNames) + bpctx.CreateVariations(osNames...) + } return } + // Bootstrap Go module support above requires this mutator to be a + // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext + // filters out non-Soong modules. Now that we've handled them, create a + // normal android.BottomUpMutatorContext. + mctx := bottomUpMutatorContextFactory(bpctx, module, false) + base := module.base() if !base.ArchSpecific() { @@ -819,13 +847,23 @@ func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module { // // Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass, // but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets(). -func archMutator(mctx BottomUpMutatorContext) { +func archMutator(bpctx blueprint.BottomUpMutatorContext) { var module Module var ok bool - if module, ok = mctx.Module().(Module); !ok { + if module, ok = bpctx.Module().(Module); !ok { + if bootstrap.IsBootstrapModule(bpctx.Module()) { + // Bootstrap Go modules are always the build architecture. + bpctx.CreateVariations(bpctx.Config().(Config).BuildOSTarget.ArchVariation()) + } return } + // Bootstrap Go module support above requires this mutator to be a + // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext + // filters out non-Soong modules. Now that we've handled them, create a + // normal android.BottomUpMutatorContext. + mctx := bottomUpMutatorContextFactory(bpctx, module, false) + base := module.base() if !base.ArchSpecific() { @@ -903,7 +941,7 @@ func archMutator(mctx BottomUpMutatorContext) { modules := mctx.CreateVariations(targetNames...) for i, m := range modules { addTargetProperties(m, targets[i], multiTargets, i == 0) - m.(Module).base().setArchProperties(mctx) + m.base().setArchProperties(mctx) } } diff --git a/android/config.go b/android/config.go index a1e97c981..dd622e5b2 100644 --- a/android/config.go +++ b/android/config.go @@ -35,6 +35,7 @@ import ( var Bool = proptools.Bool var String = proptools.String +var StringDefault = proptools.StringDefault const FutureApiLevel = 10000 @@ -958,6 +959,10 @@ func (c *deviceConfig) VndkVersion() string { return String(c.config.productVariables.DeviceVndkVersion) } +func (c *deviceConfig) CurrentApiLevelForVendorModules() string { + return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current") +} + func (c *deviceConfig) PlatformVndkVersion() string { return String(c.config.productVariables.Platform_vndk_version) } @@ -1393,7 +1398,7 @@ func splitConfiguredJarPair(ctx PathContext, str string) (string, string) { if len(pair) == 2 { return pair[0], pair[1] } else { - reportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str) + ReportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str) return "error-apex", "error-jar" } } diff --git a/android/defaults.go b/android/defaults.go index 81e340e8e..0892adfac 100644 --- a/android/defaults.go +++ b/android/defaults.go @@ -115,11 +115,6 @@ type DefaultsVisibilityProperties struct { type DefaultsModuleBase struct { DefaultableModuleBase - - // Container for defaults of the common properties - commonProperties commonProperties - - defaultsVisibilityProperties DefaultsVisibilityProperties } // The common pattern for defaults modules is to register separate instances of @@ -153,12 +148,6 @@ type Defaults interface { properties() []interface{} productVariableProperties() interface{} - - // Return the defaults common properties. - common() *commonProperties - - // Return the defaults visibility properties. - defaultsVisibility() *DefaultsVisibilityProperties } func (d *DefaultsModuleBase) isDefaults() bool { @@ -178,24 +167,17 @@ func (d *DefaultsModuleBase) productVariableProperties() interface{} { return d.defaultableVariableProperties } -func (d *DefaultsModuleBase) common() *commonProperties { - return &d.commonProperties -} - -func (d *DefaultsModuleBase) defaultsVisibility() *DefaultsVisibilityProperties { - return &d.defaultsVisibilityProperties -} - func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) { } func InitDefaultsModule(module DefaultsModule) { - commonProperties := module.common() + commonProperties := &commonProperties{} module.AddProperties( &hostAndDeviceProperties{}, commonProperties, - &ApexProperties{}) + &ApexProperties{}, + &distProperties{}) initAndroidModuleBase(module) initProductVariableModule(module) @@ -204,7 +186,7 @@ func InitDefaultsModule(module DefaultsModule) { // Add properties that will not have defaults applied to them. base := module.base() - defaultsVisibility := module.defaultsVisibility() + defaultsVisibility := &DefaultsVisibilityProperties{} module.AddProperties(&base.nameProperties, defaultsVisibility) // Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties. diff --git a/android/makevars.go b/android/makevars.go index 86f4b424b..003a9df32 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -234,7 +234,7 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { } ctx.VisitAllModules(func(m Module) { - if provider, ok := m.(ModuleMakeVarsProvider); ok { + if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled() { mctx := &makeVarsContext{ SingletonContext: ctx, } diff --git a/android/module.go b/android/module.go index b689a87f2..337ae4076 100644 --- a/android/module.go +++ b/android/module.go @@ -198,7 +198,7 @@ type ModuleContext interface { InstallInRecovery() bool InstallInRoot() bool InstallBypassMake() bool - InstallForceOS() *OsType + InstallForceOS() (*OsType, *ArchType) RequiredModuleNames() []string HostRequiredModuleNames() []string @@ -247,6 +247,7 @@ type Module interface { Disable() Enabled() bool Target() Target + Owner() string InstallInData() bool InstallInTestcases() bool InstallInSanitizerDir() bool @@ -254,10 +255,12 @@ type Module interface { InstallInRecovery() bool InstallInRoot() bool InstallBypassMake() bool - InstallForceOS() *OsType + InstallForceOS() (*OsType, *ArchType) SkipInstall() IsSkipInstall() bool MakeUninstallable() + ReplacedByPrebuilt() + IsReplacedByPrebuilt() bool ExportedToMake() bool InitRc() Paths VintfFragments() Paths @@ -490,14 +493,6 @@ type commonProperties struct { // relative path to a file to include in the list of notices for the device Notice *string `android:"path"` - // configuration to distribute output files from this module to the distribution - // directory (default: $OUT/dist, configurable with $DIST_DIR) - Dist Dist `android:"arch_variant"` - - // a list of configurations to distribute output files from this module to the - // distribution directory (default: $OUT/dist, configurable with $DIST_DIR) - Dists []Dist `android:"arch_variant"` - // The OsType of artifacts that this module variant is responsible for creating. // // Set by osMutator @@ -550,6 +545,9 @@ type commonProperties struct { SkipInstall bool `blueprint:"mutated"` + // Whether the module has been replaced by a prebuilt + ReplacedByPrebuilt bool `blueprint:"mutated"` + // Disabled by mutators. If set to true, it overrides Enabled property. ForcedDisabled bool `blueprint:"mutated"` @@ -566,6 +564,16 @@ type commonProperties struct { ImageVariation string `blueprint:"mutated"` } +type distProperties struct { + // configuration to distribute output files from this module to the distribution + // directory (default: $OUT/dist, configurable with $DIST_DIR) + Dist Dist `android:"arch_variant"` + + // a list of configurations to distribute output files from this module to the + // distribution directory (default: $OUT/dist, configurable with $DIST_DIR) + Dists []Dist `android:"arch_variant"` +} + // A map of OutputFile tag keys to Paths, for disting purposes. type TaggedDistFiles map[string]Paths @@ -661,7 +669,8 @@ func InitAndroidModule(m Module) { m.AddProperties( &base.nameProperties, - &base.commonProperties) + &base.commonProperties, + &base.distProperties) initProductVariableModule(m) @@ -752,6 +761,7 @@ type ModuleBase struct { nameProperties nameProperties commonProperties commonProperties + distProperties distProperties variableProperties interface{} hostAndDeviceProperties hostAndDeviceProperties generalProperties []interface{} @@ -861,13 +871,13 @@ func (m *ModuleBase) visibilityProperties() []visibilityProperty { } func (m *ModuleBase) Dists() []Dist { - if len(m.commonProperties.Dist.Targets) > 0 { + if len(m.distProperties.Dist.Targets) > 0 { // Make a copy of the underlying Dists slice to protect against // backing array modifications with repeated calls to this method. - distsCopy := append([]Dist(nil), m.commonProperties.Dists...) - return append(distsCopy, m.commonProperties.Dist) + distsCopy := append([]Dist(nil), m.distProperties.Dists...) + return append(distsCopy, m.distProperties.Dist) } else { - return m.commonProperties.Dists + return m.distProperties.Dists } } @@ -1063,6 +1073,15 @@ func (m *ModuleBase) MakeUninstallable() { m.SkipInstall() } +func (m *ModuleBase) ReplacedByPrebuilt() { + m.commonProperties.ReplacedByPrebuilt = true + m.SkipInstall() +} + +func (m *ModuleBase) IsReplacedByPrebuilt() bool { + return m.commonProperties.ReplacedByPrebuilt +} + func (m *ModuleBase) ExportedToMake() bool { return m.commonProperties.NamespaceExportedToMake } @@ -1116,8 +1135,8 @@ func (m *ModuleBase) InstallBypassMake() bool { return false } -func (m *ModuleBase) InstallForceOS() *OsType { - return nil +func (m *ModuleBase) InstallForceOS() (*OsType, *ArchType) { + return nil, nil } func (m *ModuleBase) Owner() string { @@ -1344,20 +1363,20 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) ctx.Variable(pctx, "moduleDescSuffix", s) // Some common property checks for properties that will be used later in androidmk.go - if m.commonProperties.Dist.Dest != nil { - _, err := validateSafePath(*m.commonProperties.Dist.Dest) + if m.distProperties.Dist.Dest != nil { + _, err := validateSafePath(*m.distProperties.Dist.Dest) if err != nil { ctx.PropertyErrorf("dist.dest", "%s", err.Error()) } } - if m.commonProperties.Dist.Dir != nil { - _, err := validateSafePath(*m.commonProperties.Dist.Dir) + if m.distProperties.Dist.Dir != nil { + _, err := validateSafePath(*m.distProperties.Dist.Dir) if err != nil { ctx.PropertyErrorf("dist.dir", "%s", err.Error()) } } - if m.commonProperties.Dist.Suffix != nil { - if strings.Contains(*m.commonProperties.Dist.Suffix, "/") { + if m.distProperties.Dist.Suffix != nil { + if strings.Contains(*m.distProperties.Dist.Suffix, "/") { ctx.PropertyErrorf("dist.suffix", "Suffix may not contain a '/' character.") } } @@ -2017,7 +2036,7 @@ func (m *moduleContext) InstallBypassMake() bool { return m.module.InstallBypassMake() } -func (m *moduleContext) InstallForceOS() *OsType { +func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) { return m.module.InstallForceOS() } @@ -2246,7 +2265,7 @@ func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) P return nil } if len(paths) > 1 { - reportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", + ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", pathContextName(ctx, module)) return nil } diff --git a/android/mutator.go b/android/mutator.go index 40e61deb2..521255328 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -75,6 +75,7 @@ type registerMutatorsContext struct { type RegisterMutatorsContext interface { TopDown(name string, m TopDownMutator) MutatorHandle BottomUp(name string, m BottomUpMutator) MutatorHandle + BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle } type RegisterMutatorFunc func(RegisterMutatorsContext) @@ -143,9 +144,9 @@ var preArch = []RegisterMutatorFunc{ } func registerArchMutator(ctx RegisterMutatorsContext) { - ctx.BottomUp("os", osMutator).Parallel() + ctx.BottomUpBlueprint("os", osMutator).Parallel() ctx.BottomUp("image", imageMutator).Parallel() - ctx.BottomUp("arch", archMutator).Parallel() + ctx.BottomUpBlueprint("arch", archMutator).Parallel() } var preDeps = []RegisterMutatorFunc{ @@ -225,16 +226,21 @@ type bottomUpMutatorContext struct { finalPhase bool } +func bottomUpMutatorContextFactory(ctx blueprint.BottomUpMutatorContext, a Module, + finalPhase bool) BottomUpMutatorContext { + + return &bottomUpMutatorContext{ + bp: ctx, + baseModuleContext: a.base().baseModuleContextFactory(ctx), + finalPhase: finalPhase, + } +} + func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle { finalPhase := x.finalPhase f := func(ctx blueprint.BottomUpMutatorContext) { if a, ok := ctx.Module().(Module); ok { - actx := &bottomUpMutatorContext{ - bp: ctx, - baseModuleContext: a.base().baseModuleContextFactory(ctx), - finalPhase: finalPhase, - } - m(actx) + m(bottomUpMutatorContextFactory(ctx, a, finalPhase)) } } mutator := &mutator{name: name, bottomUpMutator: f} @@ -242,6 +248,12 @@ func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) Mutat return mutator } +func (x *registerMutatorsContext) BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle { + mutator := &mutator{name: name, bottomUpMutator: m} + x.mutators = append(x.mutators, mutator) + return mutator +} + func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) MutatorHandle { f := func(ctx blueprint.TopDownMutatorContext) { if a, ok := ctx.Module().(Module); ok { diff --git a/android/neverallow.go b/android/neverallow.go index aaea920cc..8b8e1accf 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -199,6 +199,7 @@ func createCcSdkVariantRules() []Rule { "prebuilts/ndk", "tools/test/graphicsbenchmark/apps/sample_app", "tools/test/graphicsbenchmark/functional_tests/java", + "vendor/xts/gts-tests/hostsidetests/gamedevicecert/apps/javatests", } platformVariantPropertiesAllowedList := []string{ @@ -274,6 +275,10 @@ func neverallowMutator(ctx BottomUpMutatorContext) { continue } + if !n.appliesToBootclasspathJar(ctx) { + continue + } + ctx.ModuleErrorf("violates " + n.String()) } } @@ -332,6 +337,18 @@ func (m *regexMatcher) String() string { return ".regexp(" + m.re.String() + ")" } +type notInListMatcher struct { + allowed []string +} + +func (m *notInListMatcher) Test(value string) bool { + return !InList(value, m.allowed) +} + +func (m *notInListMatcher) String() string { + return ".not-in-list(" + strings.Join(m.allowed, ",") + ")" +} + type isSetMatcher struct{} func (m *isSetMatcher) Test(value string) bool { @@ -363,6 +380,8 @@ type Rule interface { NotModuleType(types ...string) Rule + BootclasspathJar() Rule + With(properties, value string) Rule WithMatcher(properties string, matcher ValueMatcher) Rule @@ -390,6 +409,8 @@ type rule struct { props []ruleProperty unlessProps []ruleProperty + + onlyBootclasspathJar bool } // Create a new NeverAllow rule. @@ -465,6 +486,11 @@ func (r *rule) Because(reason string) Rule { return r } +func (r *rule) BootclasspathJar() Rule { + r.onlyBootclasspathJar = true + return r +} + func (r *rule) String() string { s := "neverallow" for _, v := range r.paths { @@ -491,6 +517,9 @@ func (r *rule) String() string { for _, v := range r.osClasses { s += " os:" + v.String() } + if r.onlyBootclasspathJar { + s += " inBcp" + } if len(r.reason) != 0 { s += " which is restricted because " + r.reason } @@ -519,6 +548,14 @@ func (r *rule) appliesToDirectDeps(ctx BottomUpMutatorContext) bool { return matches } +func (r *rule) appliesToBootclasspathJar(ctx BottomUpMutatorContext) bool { + if !r.onlyBootclasspathJar { + return true + } + + return InList(ctx.ModuleName(), ctx.Config().BootJars()) +} + func (r *rule) appliesToOsClass(osClass OsClass) bool { if len(r.osClasses) == 0 { return true @@ -555,6 +592,10 @@ func Regexp(re string) ValueMatcher { return ®exMatcher{r} } +func NotInList(allowed []string) ValueMatcher { + return ¬InListMatcher{allowed} +} + // assorted utils func cleanPaths(paths []string) []string { diff --git a/android/override_module.go b/android/override_module.go index 3994084a8..f8342d52d 100644 --- a/android/override_module.go +++ b/android/override_module.go @@ -313,3 +313,15 @@ func replaceDepsOnOverridingModuleMutator(ctx BottomUpMutatorContext) { } } } + +// ModuleNameWithPossibleOverride returns the name of the OverrideModule that overrides the current +// variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule +// or if this variant is not overridden. +func ModuleNameWithPossibleOverride(ctx ModuleContext) string { + if overridable, ok := ctx.Module().(OverridableModule); ok { + if o := overridable.GetOverriddenBy(); o != "" { + return o + } + } + return ctx.ModuleName() +} diff --git a/android/paths.go b/android/paths.go index 65f129ce8..3825d45a4 100644 --- a/android/paths.go +++ b/android/paths.go @@ -61,7 +61,7 @@ type ModuleInstallPathContext interface { InstallInRecovery() bool InstallInRoot() bool InstallBypassMake() bool - InstallForceOS() *OsType + InstallForceOS() (*OsType, *ArchType) } var _ ModuleInstallPathContext = ModuleContext(nil) @@ -86,13 +86,13 @@ var _ moduleErrorf = blueprint.ModuleContext(nil) // attempts ctx.ModuleErrorf for a better error message first, then falls // back to ctx.Errorf. func reportPathError(ctx PathContext, err error) { - reportPathErrorf(ctx, "%s", err.Error()) + ReportPathErrorf(ctx, "%s", err.Error()) } -// reportPathErrorf will register an error with the attached context. It +// ReportPathErrorf will register an error with the attached context. It // attempts ctx.ModuleErrorf for a better error message first, then falls // back to ctx.Errorf. -func reportPathErrorf(ctx PathContext, format string, args ...interface{}) { +func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) { if mctx, ok := ctx.(moduleErrorf); ok { mctx.ModuleErrorf(format, args...) } else if ectx, ok := ctx.(errorfContext); ok { @@ -155,7 +155,7 @@ func GenPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) Module if path, ok := p.(genPathProvider); ok { return path.genPathWithExt(ctx, subdir, ext) } - reportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p) + ReportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p) return PathForModuleGen(ctx) } @@ -165,7 +165,7 @@ func ObjPathWithExt(ctx ModuleContext, subdir string, p Path, ext string) Module if path, ok := p.(objPathProvider); ok { return path.objPathWithExt(ctx, subdir, ext) } - reportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) + ReportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) return PathForModuleObj(ctx) } @@ -176,7 +176,7 @@ func ResPathWithName(ctx ModuleContext, p Path, name string) ModuleResPath { if path, ok := p.(resPathProvider); ok { return path.resPathWithName(ctx, name) } - reportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) + ReportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p) return PathForModuleRes(ctx) } @@ -416,9 +416,9 @@ func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (P } else { p := pathForModuleSrc(ctx, s) if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil { - reportPathErrorf(ctx, "%s: %s", p, err.Error()) + ReportPathErrorf(ctx, "%s: %s", p, err.Error()) } else if !exists && !ctx.Config().testAllowNonExistentPaths { - reportPathErrorf(ctx, "module source path %q does not exist", p) + ReportPathErrorf(ctx, "module source path %q does not exist", p) } if InList(p.String(), expandedExcludes) { @@ -445,7 +445,7 @@ func pathsForModuleSrcFromFullPath(ctx EarlyModuleContext, paths []string, incDi } path := filepath.Clean(p) if !strings.HasPrefix(path, prefix) { - reportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix) + ReportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix) continue } @@ -801,7 +801,7 @@ func PathForSource(ctx PathContext, pathComponents ...string) SourcePath { } if pathtools.IsGlob(path.String()) { - reportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) + ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) } if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() { @@ -813,9 +813,9 @@ func PathForSource(ctx PathContext, pathComponents ...string) SourcePath { modCtx.AddMissingDependencies([]string{path.String()}) } } else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil { - reportPathErrorf(ctx, "%s: %s", path, err.Error()) + ReportPathErrorf(ctx, "%s: %s", path, err.Error()) } else if !exists && !ctx.Config().testAllowNonExistentPaths { - reportPathErrorf(ctx, "source path %q does not exist", path) + ReportPathErrorf(ctx, "source path %q does not exist", path) } return path } @@ -831,7 +831,7 @@ func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPa } if pathtools.IsGlob(path.String()) { - reportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) + ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String()) return OptionalPath{} } @@ -876,17 +876,17 @@ func (p SourcePath) OverlayPath(ctx ModuleContext, path Path) OptionalPath { if srcPath, ok := path.(SourcePath); ok { relDir = srcPath.path } else { - reportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path) + ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path) return OptionalPath{} } dir := filepath.Join(p.config.srcDir, p.path, relDir) // Use Glob so that we are run again if the directory is added. if pathtools.IsGlob(dir) { - reportPathErrorf(ctx, "Path may not contain a glob: %s", dir) + ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir) } paths, err := ctx.GlobWithDeps(dir, nil) if err != nil { - reportPathErrorf(ctx, "glob: %s", err.Error()) + ReportPathErrorf(ctx, "glob: %s", err.Error()) return OptionalPath{} } if len(paths) == 0 { @@ -977,7 +977,7 @@ func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath { // ReplaceExtension creates a new OutputPath with the extension replaced with ext. func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath { if strings.Contains(ext, "/") { - reportPathErrorf(ctx, "extension %q cannot contain /", ext) + ReportPathErrorf(ctx, "extension %q cannot contain /", ext) } ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext)) ret.rel = pathtools.ReplaceExtension(p.rel, ext) @@ -1030,10 +1030,10 @@ func PathForModuleSrc(ctx ModuleContext, pathComponents ...string) Path { } return nil } else if len(paths) == 0 { - reportPathErrorf(ctx, "%q produced no files, expected exactly one", p) + ReportPathErrorf(ctx, "%q produced no files, expected exactly one", p) return nil } else if len(paths) > 1 { - reportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths)) + ReportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths)) } return paths[0] } @@ -1278,12 +1278,17 @@ func (p InstallPath) ToMakePath() InstallPath { // module appended with paths... func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath { os := ctx.Os() - if forceOS := ctx.InstallForceOS(); forceOS != nil { + arch := ctx.Arch().ArchType + forceOS, forceArch := ctx.InstallForceOS() + if forceOS != nil { os = *forceOS } + if forceArch != nil { + arch = *forceArch + } partition := modulePartition(ctx, os) - ret := pathForInstall(ctx, os, partition, ctx.Debug(), pathComponents...) + ret := pathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...) if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() { ret = ret.ToMakePath() @@ -1292,7 +1297,7 @@ func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string return ret } -func pathForInstall(ctx PathContext, os OsType, partition string, debug bool, +func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, debug bool, pathComponents ...string) InstallPath { var outPaths []string @@ -1300,15 +1305,21 @@ func pathForInstall(ctx PathContext, os OsType, partition string, debug bool, if os.Class == Device { outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition} } else { - switch os { - case Linux: - outPaths = []string{"host", "linux-x86", partition} - case LinuxBionic: - // TODO: should this be a separate top level, or shared with linux-x86? - outPaths = []string{"host", "linux_bionic-x86", partition} - default: - outPaths = []string{"host", os.String() + "-x86", partition} + osName := os.String() + if os == Linux { + // instead of linux_glibc + osName = "linux" + } + // SOONG_HOST_OUT is set to out/host/$(HOST_OS)-$(HOST_PREBUILT_ARCH) + // and HOST_PREBUILT_ARCH is forcibly set to x86 even on x86_64 hosts. We don't seem + // to have a plan to fix it (see the comment in build/make/core/envsetup.mk). + // Let's keep using x86 for the existing cases until we have a need to support + // other architectures. + archName := arch.String() + if os.Class == Host && (arch == X86_64 || arch == Common) { + archName = "x86" } + outPaths = []string{"host", osName + "-" + archName, partition} } if debug { outPaths = append([]string{"debug"}, outPaths...) @@ -1447,7 +1458,7 @@ func validatePath(pathComponents ...string) (string, error) { func PathForPhony(ctx PathContext, phony string) WritablePath { if strings.ContainsAny(phony, "$/") { - reportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony) + ReportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony) } return PhonyPath{basePath{phony, ctx.Config(), ""}} } @@ -1513,7 +1524,7 @@ func PathContextForTesting(config Config) PathContext { func Rel(ctx PathContext, basePath string, targetPath string) string { rel, isRel := MaybeRel(ctx, basePath, targetPath) if !isRel { - reportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath) + ReportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath) return "" } return rel diff --git a/android/paths_test.go b/android/paths_test.go index a9cd22bce..d099f6502 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -207,6 +207,7 @@ type moduleInstallPathContextImpl struct { inRecovery bool inRoot bool forceOS *OsType + forceArch *ArchType } func (m moduleInstallPathContextImpl) Config() Config { @@ -243,8 +244,8 @@ func (m moduleInstallPathContextImpl) InstallBypassMake() bool { return false } -func (m moduleInstallPathContextImpl) InstallForceOS() *OsType { - return m.forceOS +func (m moduleInstallPathContextImpl) InstallForceOS() (*OsType, *ArchType) { + return m.forceOS, m.forceArch } func pathTestConfig(buildDir string) Config { @@ -254,8 +255,8 @@ func pathTestConfig(buildDir string) Config { func TestPathForModuleInstall(t *testing.T) { testConfig := pathTestConfig("") - hostTarget := Target{Os: Linux} - deviceTarget := Target{Os: Android} + hostTarget := Target{Os: Linux, Arch: Arch{ArchType: X86}} + deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}} testCases := []struct { name string @@ -635,6 +636,7 @@ func TestPathForModuleInstall(t *testing.T) { }, inTestcases: true, forceOS: &Linux, + forceArch: &X86, }, in: []string{"my_test", "my_test_bin"}, out: "host/linux-x86/testcases/my_test/my_test_bin", diff --git a/android/prebuilt.go b/android/prebuilt.go index 269ad5d8a..734871b6b 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -253,7 +253,7 @@ func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) { p := m.(PrebuiltInterface).Prebuilt() if p.usePrebuilt(ctx, s) { p.properties.UsePrebuilt = true - s.SkipInstall() + s.ReplacedByPrebuilt() } }) } diff --git a/android/test_suites.go b/android/test_suites.go index 7b2d7dcd1..34e487e8e 100644 --- a/android/test_suites.go +++ b/android/test_suites.go @@ -60,7 +60,7 @@ func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) W for _, module := range SortedStringKeys(files) { installedPaths = append(installedPaths, files[module]...) } - testCasesDir := pathForInstall(ctx, BuildOs, "testcases", false).ToMakePath() + testCasesDir := pathForInstall(ctx, BuildOs, X86, "testcases", false).ToMakePath() outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip") rule := NewRuleBuilder() @@ -68,7 +68,7 @@ func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) W FlagWithOutput("-o ", outputFile). FlagWithArg("-P ", "host/testcases"). FlagWithArg("-C ", testCasesDir.String()). - FlagWithRspFileInputList("-l ", installedPaths.Paths()) + FlagWithRspFileInputList("-r ", installedPaths.Paths()) rule.Build(pctx, ctx, "robolectric_tests_zip", "robolectric-tests.zip") return outputFile diff --git a/android/testing.go b/android/testing.go index f32d745c2..8ea4168d1 100644 --- a/android/testing.go +++ b/android/testing.go @@ -187,19 +187,21 @@ func newTestingBuildParams(provider testBuildProvider, bparams BuildParams) Test } } -func maybeBuildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams { +func maybeBuildParamsFromRule(provider testBuildProvider, rule string) (TestingBuildParams, []string) { + var searchedRules []string for _, p := range provider.BuildParamsForTests() { + searchedRules = append(searchedRules, p.Rule.String()) if strings.Contains(p.Rule.String(), rule) { - return newTestingBuildParams(provider, p) + return newTestingBuildParams(provider, p), searchedRules } } - return TestingBuildParams{} + return TestingBuildParams{}, searchedRules } func buildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams { - p := maybeBuildParamsFromRule(provider, rule) + p, searchRules := maybeBuildParamsFromRule(provider, rule) if p.Rule == nil { - panic(fmt.Errorf("couldn't find rule %q", rule)) + panic(fmt.Errorf("couldn't find rule %q.\nall rules: %v", rule, searchRules)) } return p } @@ -275,7 +277,8 @@ func (m TestingModule) Module() Module { // MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty // BuildParams if no rule is found. func (m TestingModule) MaybeRule(rule string) TestingBuildParams { - return maybeBuildParamsFromRule(m.module, rule) + r, _ := maybeBuildParamsFromRule(m.module, rule) + return r } // Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found. @@ -328,7 +331,8 @@ func (s TestingSingleton) Singleton() Singleton { // MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty // BuildParams if no rule is found. func (s TestingSingleton) MaybeRule(rule string) TestingBuildParams { - return maybeBuildParamsFromRule(s.provider, rule) + r, _ := maybeBuildParamsFromRule(s.provider, rule) + return r } // Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found. @@ -394,7 +398,7 @@ func FailIfNoMatchingErrors(t *testing.T, pattern string, errs []error) { if !found { t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs)) for i, err := range errs { - t.Errorf("errs[%d] = %s", i, err) + t.Errorf("errs[%d] = %q", i, err) } } } diff --git a/android/util.go b/android/util.go index 8dbf21459..65c5f1b28 100644 --- a/android/util.go +++ b/android/util.go @@ -79,6 +79,20 @@ func JoinWithSuffix(strs []string, suffix string, separator string) string { return string(ret) } +func SortedIntKeys(m interface{}) []int { + v := reflect.ValueOf(m) + if v.Kind() != reflect.Map { + panic(fmt.Sprintf("%#v is not a map", m)) + } + keys := v.MapKeys() + s := make([]int, 0, len(keys)) + for _, key := range keys { + s = append(s, int(key.Int())) + } + sort.Ints(s) + return s +} + func SortedStringKeys(m interface{}) []string { v := reflect.ValueOf(m) if v.Kind() != reflect.Map { diff --git a/android/variable.go b/android/variable.go index 1f21f3498..53f081e8c 100644 --- a/android/variable.go +++ b/android/variable.go @@ -166,13 +166,14 @@ type productVariables struct { Platform_min_supported_target_sdk_version *string `json:",omitempty"` Platform_base_os *string `json:",omitempty"` - DeviceName *string `json:",omitempty"` - DeviceArch *string `json:",omitempty"` - DeviceArchVariant *string `json:",omitempty"` - DeviceCpuVariant *string `json:",omitempty"` - DeviceAbi []string `json:",omitempty"` - DeviceVndkVersion *string `json:",omitempty"` - DeviceSystemSdkVersions []string `json:",omitempty"` + DeviceName *string `json:",omitempty"` + DeviceArch *string `json:",omitempty"` + DeviceArchVariant *string `json:",omitempty"` + DeviceCpuVariant *string `json:",omitempty"` + DeviceAbi []string `json:",omitempty"` + DeviceVndkVersion *string `json:",omitempty"` + DeviceCurrentApiLevelForVendorModules *string `json:",omitempty"` + DeviceSystemSdkVersions []string `json:",omitempty"` DeviceSecondaryArch *string `json:",omitempty"` DeviceSecondaryArchVariant *string `json:",omitempty"` diff --git a/apex/Android.bp b/apex/Android.bp index 144f44197..1a5f6837e 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -5,6 +5,7 @@ bootstrap_go_package { "blueprint", "soong", "soong-android", + "soong-bpf", "soong-cc", "soong-java", "soong-python", diff --git a/apex/androidmk.go b/apex/androidmk.go index 5c6d6ccfe..1b53a672b 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -36,7 +36,9 @@ func (a *apexBundle) AndroidMk() android.AndroidMkData { return a.androidMkForType() } -func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string) []string { +func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string, + apexAndroidMkData android.AndroidMkData) []string { + // apexBundleName comes from the 'name' property; apexName comes from 'apex_name' property. // An apex is installed to /system/apex/<apexBundleName> and is activated at /apex/<apexName> // In many cases, the two names are the same, but could be different in general. @@ -108,6 +110,9 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) } fmt.Fprintln(w, "LOCAL_MODULE :=", moduleName) + if fi.module != nil && fi.module.Owner() != "" { + fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", fi.module.Owner()) + } // /apex/<apex_name>/{lib|framework|...} pathWhenActivated := filepath.Join("$(PRODUCT_OUT)", "apex", apexName, fi.installDir) var modulePath string @@ -233,6 +238,17 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, mo fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem()) if fi.builtFile == a.manifestPbOut && apexType == flattenedApex { if a.primaryApexType { + // To install companion files (init_rc, vintf_fragments) + // Copy some common properties of apexBundle to apex_manifest + commonProperties := []string{ + "LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS", + } + for _, name := range commonProperties { + if value, ok := apexAndroidMkData.Entries.EntryMap[name]; ok { + fmt.Fprintln(w, name+" := "+strings.Join(value, " ")) + } + } + // Make apex_manifest.pb module for this APEX to override all other // modules in the APEXes being overridden by this APEX var patterns []string @@ -291,7 +307,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { apexType := a.properties.ApexType if a.installable() { apexName := proptools.StringDefault(a.properties.Apex_name, name) - moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir) + moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir, data) } if apexType == flattenedApex { diff --git a/apex/apex.go b/apex/apex.go index 1267ec758..8e35e07c0 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -26,6 +26,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/bpf" "android/soong/cc" prebuilt_etc "android/soong/etc" "android/soong/java" @@ -41,6 +42,9 @@ const ( imageApexType = "image" zipApexType = "zip" flattenedApexType = "flattened" + + ext4FsType = "ext4" + f2fsFsType = "f2fs" ) type dependencyTag struct { @@ -63,6 +67,7 @@ var ( usesTag = dependencyTag{name: "uses"} androidAppTag = dependencyTag{name: "androidApp", payload: true} rroTag = dependencyTag{name: "rro", payload: true} + bpfTag = dependencyTag{name: "bpf", payload: true} apexAvailBaseline = makeApexAvailableBaseline() @@ -95,6 +100,13 @@ func makeApexAvailableBaseline() map[string][]string { // // Module separator // + m["com.android.appsearch"] = []string{ + "icing-java-proto-lite", + "libprotobuf-java-lite", + } + // + // Module separator + // m["com.android.bluetooth.updatable"] = []string{ "android.hardware.audio.common@5.0", "android.hardware.bluetooth.a2dp@1.0", @@ -177,6 +189,19 @@ func makeApexAvailableBaseline() map[string][]string { // // Module separator // + m["com.android.extservices"] = []string{ + "error_prone_annotations", + "ExtServices-core", + "ExtServices", + "libtextclassifier-java", + "libz_current", + "textclassifier-statsd", + "TextClassifierNotificationLibNoManifest", + "TextClassifierServiceLibNoManifest", + } + // + // Module separator + // m["com.android.neuralnetworks"] = []string{ "android.hardware.neuralnetworks@1.0", "android.hardware.neuralnetworks@1.1", @@ -292,7 +317,6 @@ func makeApexAvailableBaseline() map[string][]string { "libpdx_headers", "libpdx_uds", "libprocinfo", - "libsonivox", "libspeexresampler", "libspeexresampler", "libstagefright_esds", @@ -329,6 +353,7 @@ func makeApexAvailableBaseline() map[string][]string { "android.hardware.configstore@1.1", "android.hardware.graphics.allocator@2.0", "android.hardware.graphics.allocator@3.0", + "android.hardware.graphics.allocator@4.0", "android.hardware.graphics.bufferqueue@1.0", "android.hardware.graphics.bufferqueue@2.0", "android.hardware.graphics.common-ndk_platform", @@ -341,6 +366,7 @@ func makeApexAvailableBaseline() map[string][]string { "android.hardware.graphics.mapper@4.0", "android.hardware.media.bufferpool@2.0", "android.hardware.media.c2@1.0", + "android.hardware.media.c2@1.1", "android.hardware.media.omx@1.0", "android.hardware.media@1.0", "android.hardware.media@1.0", @@ -434,6 +460,7 @@ func makeApexAvailableBaseline() map[string][]string { "libpdx_headers", "libscudo_wrapper", "libsfplugin_ccodec_utils", + "libspeexresampler", "libstagefright_amrnb_common", "libstagefright_amrnbdec", "libstagefright_amrnbenc", @@ -476,6 +503,8 @@ func makeApexAvailableBaseline() map[string][]string { // Module separator // m["com.android.permission"] = []string{ + "car-ui-lib", + "iconloader", "kotlin-annotations", "kotlin-stdlib", "kotlin-stdlib-jdk7", @@ -485,6 +514,17 @@ func makeApexAvailableBaseline() map[string][]string { "kotlinx-coroutines-core", "kotlinx-coroutines-core-nodeps", "permissioncontroller-statsd", + "GooglePermissionController", + "PermissionController", + "SettingsLibActionBarShadow", + "SettingsLibAppPreference", + "SettingsLibBarChartPreference", + "SettingsLibLayoutPreference", + "SettingsLibProgressBar", + "SettingsLibSearchWidget", + "SettingsLibSettingsTheme", + "SettingsLibRestrictedLockUtils", + "SettingsLibHelpUtils", } // // Module separator @@ -643,6 +683,55 @@ func makeApexAvailableBaseline() map[string][]string { return m } +// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART. +// Adding code to the bootclasspath in new packages will cause issues on module update. +func qModulesPackages() map[string][]string { + return map[string][]string{ + "com.android.conscrypt": []string{ + "android.net.ssl", + "com.android.org.conscrypt", + }, + "com.android.media": []string{ + "android.media", + }, + } +} + +// DO NOT EDIT! These are the package prefixes that are exempted from being AOT'ed by ART. +// Adding code to the bootclasspath in new packages will cause issues on module update. +func rModulesPackages() map[string][]string { + return map[string][]string{ + "com.android.mediaprovider": []string{ + "android.provider", + }, + "com.android.permission": []string{ + "android.permission", + "android.app.role", + "com.android.permission", + "com.android.role", + }, + "com.android.sdkext": []string{ + "android.os.ext", + }, + "com.android.os.statsd": []string{ + "android.app", + "android.os", + "android.util", + "com.android.internal.statsd", + "com.android.server.stats", + }, + "com.android.wifi": []string{ + "com.android.server.wifi", + "com.android.wifi.x", + "android.hardware.wifi", + "android.net.wifi", + }, + "com.android.tethering": []string{ + "android.net", + }, + } +} + func init() { android.RegisterModuleType("apex", BundleFactory) android.RegisterModuleType("apex_test", testApexBundleFactory) @@ -660,6 +749,24 @@ func init() { sort.Strings(*apexFileContextsInfos) ctx.Strict("APEX_FILE_CONTEXTS_INFOS", strings.Join(*apexFileContextsInfos, " ")) }) + + android.AddNeverAllowRules(createApexPermittedPackagesRules(qModulesPackages())...) + android.AddNeverAllowRules(createApexPermittedPackagesRules(rModulesPackages())...) +} + +func createApexPermittedPackagesRules(modules_packages map[string][]string) []android.Rule { + rules := make([]android.Rule, 0, len(modules_packages)) + for module_name, module_packages := range modules_packages { + permitted_packages_rule := android.NeverAllow(). + BootclasspathJar(). + With("apex_available", module_name). + WithMatcher("permitted_packages", android.NotInList(module_packages)). + Because("jars that are part of the " + module_name + + " module may only allow these packages: " + strings.Join(module_packages, ",") + + ". Please jarjar or move code around.") + rules = append(rules, permitted_packages_rule) + } + return rules } func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { @@ -669,6 +776,7 @@ func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { ctx.TopDown("apex_deps", apexDepsMutator).Parallel() + ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel() ctx.BottomUp("apex", apexMutator).Parallel() ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel() ctx.BottomUp("apex_uses", apexUsesMutator).Parallel() @@ -688,7 +796,9 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { apexInfo := android.ApexInfo{ ApexVariationName: mctx.ModuleName(), MinSdkVersion: a.minSdkVersion(mctx), + RequiredSdks: a.RequiredSdks(), Updatable: a.Updatable(), + InApexes: []string{mctx.ModuleName()}, } useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface()) @@ -721,6 +831,17 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) { }) } +func apexUniqueVariationsMutator(mctx android.BottomUpMutatorContext) { + if !mctx.Module().Enabled() { + return + } + if am, ok := mctx.Module().(android.ApexModule); ok { + // Check if any dependencies use unique apex variations. If so, use unique apex variations + // for this module. + am.UpdateUniqueApexVariationsForDeps(mctx) + } +} + // mark if a module cannot be available to platform. A module cannot be available // to platform if 1) it is explicitly marked as not available (i.e. "//apex_available:platform" // is absent) or 2) it depends on another module that isn't (or can't be) available to platform @@ -733,18 +854,6 @@ func markPlatformAvailability(mctx android.BottomUpMutatorContext) { if am, ok := mctx.Module().(android.ApexModule); ok { availableToPlatform := am.AvailableFor(android.AvailableToPlatform) - // In a rare case when a lib is marked as available only to an apex - // but the apex doesn't exist. This can happen in a partial manifest branch - // like master-art. Currently, libstatssocket in the stats APEX is causing - // this problem. - // Include the lib in platform because the module SDK that ought to provide - // it doesn't exist, so it would otherwise be left out completely. - // TODO(b/154888298) remove this by adding those libraries in module SDKS and skipping - // this check for libraries provided by SDKs. - if !availableToPlatform && !android.InAnyApex(am.Name()) { - availableToPlatform = true - } - // If any of the dep is not available to platform, this module is also considered // as being not available to platform even if it has "//apex_available:platform" mctx.VisitDirectDeps(func(child android.Module) { @@ -956,6 +1065,9 @@ type apexBundleProperties struct { // List of prebuilt files that are embedded inside this APEX bundle Prebuilts []string + // List of BPF programs inside APEX + Bpfs []string + // Name of the apex_key module that provides the private key to sign APEX Key *string @@ -1026,6 +1138,10 @@ type apexBundleProperties struct { // Should be only used in non-system apexes (e.g. vendor: true). // Default is false. Use_vndk_as_stable *bool + + // The type of filesystem to use for an image apex. Either 'ext4' or 'f2fs'. + // Default 'ext4'. + Payload_fs_type *string } type apexTargetBundleProperties struct { @@ -1175,6 +1291,8 @@ type apexFile struct { overriddenPackageName string // only for apps isJniLib bool + + noticeFiles android.Paths } func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidMkModuleName string, installDir string, class apexFileClass, module android.Module) apexFile { @@ -1190,6 +1308,7 @@ func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidM ret.requiredModuleNames = module.RequiredModuleNames() ret.targetRequiredModuleNames = module.TargetRequiredModuleNames() ret.hostRequiredModuleNames = module.HostRequiredModuleNames() + ret.noticeFiles = module.NoticeFiles() } return ret } @@ -1233,6 +1352,24 @@ func (af *apexFile) AvailableToPlatform() bool { return false } +type fsType int + +const ( + ext4 fsType = iota + f2fs +) + +func (f fsType) string() string { + switch f { + case ext4: + return ext4FsType + case f2fs: + return f2fsFsType + default: + panic(fmt.Errorf("unknown APEX payload type %d", f)) + } +} + type apexBundle struct { android.ModuleBase android.DefaultableModuleBase @@ -1298,6 +1435,8 @@ type apexBundle struct { // Optional list of lint report zip files for apexes that contain java or app modules lintReports android.Paths + + payloadFsType fsType } func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, @@ -1307,26 +1446,26 @@ func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, // conflicting variations with this module. This is required since // arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64' // for native shared libs. - ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "image", Variation: imageVariation}, - {Mutator: "link", Variation: "shared"}, - {Mutator: "version", Variation: ""}, // "" is the non-stub variant - }...), sharedLibTag, nativeModules.Native_shared_libs...) - ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "image", Variation: imageVariation}, - {Mutator: "link", Variation: "shared"}, - {Mutator: "version", Variation: ""}, // "" is the non-stub variant - }...), jniLibTag, nativeModules.Jni_libs...) + binVariations := target.Variations() + libVariations := append(target.Variations(), + blueprint.Variation{Mutator: "link", Variation: "shared"}) + + if ctx.Device() { + binVariations = append(binVariations, + blueprint.Variation{Mutator: "image", Variation: imageVariation}) + libVariations = append(libVariations, + blueprint.Variation{Mutator: "image", Variation: imageVariation}, + blueprint.Variation{Mutator: "version", Variation: ""}) // "" is the non-stub variant + } + + ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...) - ctx.AddFarVariationDependencies(append(target.Variations(), - blueprint.Variation{Mutator: "image", Variation: imageVariation}), - executableTag, nativeModules.Binaries...) + ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...) - ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "image", Variation: imageVariation}, - {Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant - }...), testTag, nativeModules.Tests...) + ctx.AddFarVariationDependencies(binVariations, executableTag, nativeModules.Binaries...) + + ctx.AddFarVariationDependencies(binVariations, testTag, nativeModules.Tests...) } func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) { @@ -1444,6 +1583,9 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), javaLibTag, a.properties.Java_libs...) + ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), + bpfTag, a.properties.Bpfs...) + // With EMMA_INSTRUMENT_FRAMEWORK=true the ART boot image includes jacoco library. if a.artApex && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), @@ -1711,7 +1853,7 @@ func apexFileForJavaLibrary(ctx android.BaseModuleContext, module javaModule) ap } func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, depName string) apexFile { - dirInApex := filepath.Join("etc", prebuilt.SubDir()) + dirInApex := filepath.Join(prebuilt.BaseDir(), prebuilt.SubDir()) fileToCopy := prebuilt.OutputFile() return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt) } @@ -1764,6 +1906,11 @@ func apexFileForRuntimeResourceOverlay(ctx android.BaseModuleContext, rro java.R return af } +func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, bpfProgram bpf.BpfModule) apexFile { + dirInApex := filepath.Join("etc", "bpf") + return newApexFile(ctx, builtFile, builtFile.Base(), dirInApex, etc, bpfProgram) +} + // Context "decorator", overriding the InstallBypassMake method to always reply `true`. type flattenedApexContext struct { android.ModuleContext @@ -1797,7 +1944,7 @@ func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.Paylo } // Check for the indirect dependencies if it is considered as part of the APEX - if am.ApexVariationName() != "" { + if android.InList(ctx.ModuleName(), am.InApexes()) { return do(ctx, parent, am, false /* externalDep */) } @@ -1922,13 +2069,6 @@ func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext return false } - // TODO(jiyong) remove this check when R is published to AOSP. Currently, libstatssocket - // is capable of providing a stub variant, but is being statically linked from the bluetooth - // APEX. - if toName == "libstatssocket" { - return false - } - // The dynamic linker and crash_dump tool in the runtime APEX is the only exception to this rule. // It can't make the static dependencies dynamic because it can't // do the dynamic linking for itself. @@ -2099,6 +2239,15 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { } else { ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName) } + case bpfTag: + if bpfProgram, ok := child.(bpf.BpfModule); ok { + filesToCopy, _ := bpfProgram.OutputFiles("") + for _, bpfFile := range filesToCopy { + filesInfo = append(filesInfo, apexFileForBpfProgram(ctx, bpfFile, bpfProgram)) + } + } else { + ctx.PropertyErrorf("bpfs", "%q is not a bpf module", depName) + } case prebuiltTag: if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok { filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName)) @@ -2270,6 +2419,15 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.installDir = android.PathForModuleInstall(ctx, "apex") a.filesInfo = filesInfo + switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) { + case ext4FsType: + a.payloadFsType = ext4 + case f2fsFsType: + a.payloadFsType = f2fs + default: + ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs]", *a.properties.Payload_fs_type) + } + // Optimization. If we are building bundled APEX, for the files that are gathered due to the // transitive dependencies, don't place them inside the APEX, but place a symlink pointing // the same library in the system partition, thus effectively sharing the same libraries diff --git a/apex/apex_test.go b/apex/apex_test.go index d13ec5f9f..610f66750 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -27,6 +27,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/bpf" "android/soong/cc" "android/soong/dexpreopt" prebuilt_etc "android/soong/etc" @@ -248,7 +249,7 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr ctx.RegisterModuleType("cc_test", cc.TestFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory) ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory) - ctx.RegisterModuleType("prebuilt_etc", prebuilt_etc.PrebuiltEtcFactory) + prebuilt_etc.RegisterPrebuiltEtcBuildComponents(ctx) ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory) ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory) ctx.RegisterModuleType("filegroup", android.FileGroupFactory) @@ -257,6 +258,7 @@ func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*andr java.RegisterAppBuildComponents(ctx) java.RegisterSdkLibraryBuildComponents(ctx) ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory) + ctx.RegisterModuleType("bpf", bpf.BpfFactory) ctx.PreDepsMutators(RegisterPreDepsMutators) ctx.PostDepsMutators(RegisterPostDepsMutators) @@ -528,13 +530,13 @@ func TestBasicApex(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_apex10000") // Ensure that apex variant is created for the indirect dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") @@ -606,6 +608,7 @@ func TestDefaults(t *testing.T) { java_libs: ["myjar"], apps: ["AppFoo"], rros: ["rro"], + bpfs: ["bpf"], } prebuilt_etc { @@ -652,6 +655,11 @@ func TestDefaults(t *testing.T) { theme: "blue", } + bpf { + name: "bpf", + srcs: ["bpf.c", "bpf2.c"], + } + `) ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ "etc/myetc", @@ -659,6 +667,8 @@ func TestDefaults(t *testing.T) { "lib64/mylib.so", "app/AppFoo/AppFoo.apk", "overlay/blue/rro.apk", + "etc/bpf/bpf.o", + "etc/bpf/bpf2.o", }) } @@ -723,10 +733,10 @@ func TestBasicZipApex(t *testing.T) { ensureContains(t, zipApexRule.Output.String(), "myapex.zipapex.unsigned") // Ensure that APEX variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") // Ensure that APEX variant is created for the indirect dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.zipapex/lib64/mylib.so") @@ -800,7 +810,7 @@ func TestApexWithStubs(t *testing.T) { // Ensure that direct stubs dep is included ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with the latest version of stubs for mylib2 ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_3/mylib2.so") @@ -808,9 +818,9 @@ func TestApexWithStubs(t *testing.T) { ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex) - ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_myapex/mylib3.so") + ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex10000/mylib3.so") // .. and not linking to the stubs variant of mylib3 - ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so") + ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12/mylib3.so") // Ensure that stubs libs are built without -include flags mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] @@ -890,7 +900,7 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { // Ensure that dependency of stubs is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex2").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with version 10 of libfoo ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10/libfoo.so") @@ -1110,18 +1120,21 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { testcases := []struct { name string minSdkVersion string + apexVariant string shouldLink string shouldNotLink []string }{ { name: "should link to the latest", minSdkVersion: "", + apexVariant: "apex10000", shouldLink: "30", shouldNotLink: []string{"29"}, }, { name: "should link to llndk#29", minSdkVersion: "min_sdk_version: \"29\",", + apexVariant: "apex29", shouldLink: "29", shouldNotLink: []string{"30"}, }, @@ -1180,13 +1193,13 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"] ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so") for _, ver := range tc.shouldNotLink { ensureNotContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so") } - mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink) }) } @@ -1241,9 +1254,9 @@ func TestApexWithSystemLibsStubs(t *testing.T) { // Ensure that libc is not included (since it has stubs and not listed in native_shared_libs) ensureNotContains(t, copyCmds, "image.apex/lib64/bionic/libc.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"] - mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] - mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_myapex").Rule("cc").Args["cFlags"] + mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] + mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_apex10000").Rule("cc").Args["cFlags"] // For dependency to libc // Ensure that mylib is linking with the latest version of stubs @@ -1256,7 +1269,7 @@ func TestApexWithSystemLibsStubs(t *testing.T) { // For dependency to libm // Ensure that mylib is linking with the non-stub (impl) variant - ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_myapex/libm.so") + ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_apex10000/libm.so") // ... and not linking to the stub variant ensureNotContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_29/libm.so") // ... and is not compiling with the stub @@ -1270,7 +1283,7 @@ func TestApexWithSystemLibsStubs(t *testing.T) { ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_28/libdl.so") ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_29/libdl.so") // ... and not linking to the non-stub (impl) variant - ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_myapex/libdl.so") + ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_apex10000/libdl.so") // ... Cflags from stub is correctly exported to mylib ensureContains(t, mylibCFlags, "__LIBDL_API__=27") ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27") @@ -1359,13 +1372,13 @@ func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) // platform liba is linked to non-stub version expectLink("liba", "shared", "libz", "shared") // liba in myapex is linked to #28 - expectLink("liba", "shared_myapex", "libz", "shared_28") - expectNoLink("liba", "shared_myapex", "libz", "shared_30") - expectNoLink("liba", "shared_myapex", "libz", "shared") + expectLink("liba", "shared_apex29", "libz", "shared_28") + expectNoLink("liba", "shared_apex29", "libz", "shared_30") + expectNoLink("liba", "shared_apex29", "libz", "shared") // liba in otherapex is linked to #30 - expectLink("liba", "shared_otherapex", "libz", "shared_30") - expectNoLink("liba", "shared_otherapex", "libz", "shared_28") - expectNoLink("liba", "shared_otherapex", "libz", "shared") + expectLink("liba", "shared_apex30", "libz", "shared_30") + expectNoLink("liba", "shared_apex30", "libz", "shared_28") + expectNoLink("liba", "shared_apex30", "libz", "shared") } func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { @@ -1418,9 +1431,9 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { // to distinguish them from finalized and future_api(10000) // In this test, "R" is assumed not finalized yet( listed in Platform_version_active_codenames) and translated into 9000 // (refer android/api_levels.go) - expectLink("libx", "shared_myapex", "libz", "shared_9000") - expectNoLink("libx", "shared_myapex", "libz", "shared_29") - expectNoLink("libx", "shared_myapex", "libz", "shared") + expectLink("libx", "shared_apex10000", "libz", "shared_9000") + expectNoLink("libx", "shared_apex10000", "libz", "shared_29") + expectNoLink("libx", "shared_apex10000", "libz", "shared") } func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) { @@ -1463,9 +1476,9 @@ func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libx", "shared_myapex", "libz", "shared_2") - expectNoLink("libx", "shared_myapex", "libz", "shared_1") - expectNoLink("libx", "shared_myapex", "libz", "shared") + expectLink("libx", "shared_apex10000", "libz", "shared_2") + expectNoLink("libx", "shared_apex10000", "libz", "shared_1") + expectNoLink("libx", "shared_apex10000", "libz", "shared") } func TestPlatformUsesLatestStubsFromApexes(t *testing.T) { @@ -1549,7 +1562,7 @@ func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { libFlags := ld.Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30") + expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_30") } func TestQTargetApexUsesStaticUnwinder(t *testing.T) { @@ -1575,7 +1588,7 @@ func TestQTargetApexUsesStaticUnwinder(t *testing.T) { `) // ensure apex variant of c++ is linked with static unwinder - cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module) + cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_apex29").Module().(*cc.Module) ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped") // note that platform variant is not. cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module) @@ -1937,8 +1950,8 @@ func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion libFlags := ld.Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("mylib", "shared_myapex", "mylib2", "shared_29") - expectLink("mylib", "shared_otherapex", "mylib2", "shared_otherapex") + expectLink("mylib", "shared_apex29", "mylib2", "shared_29") + expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30") } func TestFilesInSubDir(t *testing.T) { @@ -2107,12 +2120,12 @@ func TestUseVendor(t *testing.T) { inputsString := strings.Join(inputsList, " ") // ensure that the apex includes vendor variants of the direct and indirect deps - ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib.so") - ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib2.so") + ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib.so") + ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib2.so") // ensure that the apex does not include core variants - ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib.so") - ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib2.so") + ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib.so") + ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib2.so") } func TestUseVendorNotAllowedForSystemApexes(t *testing.T) { @@ -2250,13 +2263,13 @@ func TestVendorApex_use_vndk_as_stable(t *testing.T) { vendorVariant := "android_vendor.VER_arm64_armv8-a" - ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_myapex").Rule("ld") + ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_apex10000").Rule("ld") libs := names(ldRule.Args["libFlags"]) // VNDK libs(libvndk/libc++) as they are ensureListContains(t, libs, buildDir+"/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so") ensureListContains(t, libs, buildDir+"/.intermediates/libc++/"+vendorVariant+"_shared/libc++.so") // non-stable Vendor libs as APEX variants - ensureListContains(t, libs, buildDir+"/.intermediates/libvendor/"+vendorVariant+"_shared_myapex/libvendor.so") + ensureListContains(t, libs, buildDir+"/.intermediates/libvendor/"+vendorVariant+"_shared_apex10000/libvendor.so") // VNDK libs are not included when use_vndk_as_stable: true ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ @@ -2269,6 +2282,32 @@ func TestVendorApex_use_vndk_as_stable(t *testing.T) { ensureListContains(t, requireNativeLibs, ":vndk") } +func TestVendorApex_withPrebuiltFirmware(t *testing.T) { + ctx, _ := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + prebuilts: ["myfirmware"], + vendor: true, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + prebuilt_firmware { + name: "myfirmware", + src: "myfirmware.bin", + filename_from_src: true, + vendor: true, + } + `) + + ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ + "firmware/myfirmware.bin", + }) +} + func TestAndroidMk_UseVendorRequired(t *testing.T) { ctx, config := testApex(t, ` apex { @@ -2633,7 +2672,21 @@ func TestMacro(t *testing.T) { "myapex", "otherapex", ], + static_libs: ["mylib3"], + recovery_available: true, + min_sdk_version: "29", + } + cc_library { + name: "mylib3", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ + "myapex", + "otherapex", + ], use_apex_name_macro: true, + recovery_available: true, min_sdk_version: "29", } `) @@ -2644,19 +2697,43 @@ func TestMacro(t *testing.T) { ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined - mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined - mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex29").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=29") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") - // When cc_library sets use_apex_name_macro: true - // apex variants define additional macro to distinguish which apex variant it is built for + // When a cc_library sets use_apex_name_macro: true each apex gets a unique variant and + // each variant defines additional macros to distinguish which apex variant it is built for + + // non-APEX variant does not have __ANDROID_APEX__ defined + mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") + + // APEX variant has __ANDROID_APEX__ defined + mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + + // APEX variant has __ANDROID_APEX__ defined + mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"] + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") + ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + + // recovery variant does not set __ANDROID_SDK_VERSION__ + mylibCFlags = ctx.ModuleForTests("mylib3", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") + + // When a dependency of a cc_library sets use_apex_name_macro: true each apex gets a unique + // variant. // non-APEX variant does not have __ANDROID_APEX__ defined mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] @@ -2665,17 +2742,17 @@ func TestMacro(t *testing.T) { // APEX variant has __ANDROID_APEX__ defined mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") - ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") // APEX variant has __ANDROID_APEX__ defined mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__") - ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") + ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__") // recovery variant does not set __ANDROID_SDK_VERSION__ - mylibCFlags = ctx.ModuleForTests("mylib", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests("mylib2", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__") } @@ -3455,7 +3532,7 @@ func TestNonTestApex(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so") @@ -3511,7 +3588,7 @@ func TestTestApex(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib_common_test.so") @@ -3595,9 +3672,9 @@ func TestApexWithTarget(t *testing.T) { ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned") // Ensure that apex variant is created for the direct dep - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex") - ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000") + ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000") // Ensure that both direct and indirect deps are copied into apex ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") @@ -4062,8 +4139,8 @@ func TestApexUsesOtherApex(t *testing.T) { apexRule2 := module2.Rule("apexRule") copyCmds2 := apexRule2.Args["copy_commands"] - ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex") - ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_commonapex") + ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000") + ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_apex10000") ensureContains(t, copyCmds1, "image.apex/lib64/mylib.so") ensureContains(t, copyCmds2, "image.apex/lib64/libcommon.so") ensureNotContains(t, copyCmds1, "image.apex/lib64/libcommon.so") @@ -4243,14 +4320,14 @@ func TestApexWithApps(t *testing.T) { ensureContains(t, copyCmds, "image.apex/app/AppFoo/AppFoo.apk") ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk") - appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni libs") + appZipRule := ctx.ModuleForTests("AppFoo", "android_common_apex10000").Description("zip jni libs") // JNI libraries are uncompressed if args := appZipRule.Args["jarArgs"]; !strings.Contains(args, "-L 0") { t.Errorf("jni libs are not uncompressed for AppFoo") } // JNI libraries including transitive deps are for _, jni := range []string{"libjni", "libfoo"} { - jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile() + jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_apex10000").Module().(*cc.Module).OutputFile() // ... embedded inside APK (jnilibs.zip) ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String()) // ... and not directly inside the APEX @@ -4764,7 +4841,7 @@ func TestLegacyAndroid10Support(t *testing.T) { // the dependency names directly here but for some reason the names are blank in // this test. for _, lib := range []string{"libc++", "mylib"} { - apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_myapex").Rule("ld").Implicits + apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_apex29").Rule("ld").Implicits nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits if len(apexImplicits) != len(nonApexImplicits)+1 { t.Errorf("%q missing unwinder dep", lib) @@ -5358,29 +5435,6 @@ func TestApexMutatorsDontRunIfDisabled(t *testing.T) { } } -func TestApexWithJniLibs_Errors(t *testing.T) { - testApexError(t, `jni_libs: "xxx" is not a cc_library`, ` - apex { - name: "myapex", - key: "myapex.key", - jni_libs: ["xxx"], - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - prebuilt_etc { - name: "xxx", - src: "xxx", - } - `, withFiles(map[string][]byte{ - "xxx": nil, - })) -} - func TestAppBundle(t *testing.T) { ctx, _ := testApex(t, ` apex { @@ -5616,7 +5670,7 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { }) t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) { - err = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image" + err = `module "some-art-lib" from updatable apexes \["com.android.art.something"\] is not allowed in the framework boot image` transform = func(config *dexpreopt.GlobalConfig) { config.BootJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"}) } @@ -5624,7 +5678,7 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { }) t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { - err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image" + err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image` transform = func(config *dexpreopt.GlobalConfig) { config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"}) } @@ -5632,7 +5686,7 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { }) t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) { - err = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image" + err = `module "some-non-updatable-apex-lib" is not allowed in the ART boot image` transform = func(config *dexpreopt.GlobalConfig) { config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"}) } @@ -5640,7 +5694,7 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { }) t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) { - err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image" + err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image` transform = func(config *dexpreopt.GlobalConfig) { config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"}) } @@ -5671,7 +5725,7 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { }) t.Run("platform jar in the ART boot image => error", func(t *testing.T) { - err = "module 'some-platform-lib' is not allowed in the ART boot image" + err = `module "some-platform-lib" is not allowed in the ART boot image` transform = func(config *dexpreopt.GlobalConfig) { config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"}) } @@ -5686,6 +5740,141 @@ func TestNoUpdatableJarsInBootImage(t *testing.T) { }) } +func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, apexBootJars []string, rules []android.Rule) { + t.Helper() + android.ClearApexDependency() + bp += ` + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + }` + fs := map[string][]byte{ + "lib1/src/A.java": nil, + "lib2/src/B.java": nil, + "system/sepolicy/apex/myapex-file_contexts": nil, + } + + ctx := android.NewTestArchContext() + ctx.RegisterModuleType("apex", BundleFactory) + ctx.RegisterModuleType("apex_key", ApexKeyFactory) + ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) + cc.RegisterRequiredBuildComponentsForTest(ctx) + java.RegisterJavaBuildComponents(ctx) + java.RegisterSystemModulesBuildComponents(ctx) + java.RegisterDexpreoptBootJarsComponents(ctx) + ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) + ctx.PreDepsMutators(RegisterPreDepsMutators) + ctx.PostDepsMutators(RegisterPostDepsMutators) + ctx.PostDepsMutators(android.RegisterNeverallowMutator) + + config := android.TestArchConfig(buildDir, nil, bp, fs) + android.SetTestNeverallowRules(config, rules) + updatableBootJars := make([]string, 0, len(apexBootJars)) + for _, apexBootJar := range apexBootJars { + updatableBootJars = append(updatableBootJars, "myapex:"+apexBootJar) + } + config.TestProductVariables.UpdatableBootJars = updatableBootJars + + ctx.Register(config) + + _, errs := ctx.ParseBlueprintsFiles("Android.bp") + android.FailIfErrored(t, errs) + + _, errs = ctx.PrepareBuildActions(config) + if errmsg == "" { + android.FailIfErrored(t, errs) + } else if len(errs) > 0 { + android.FailIfNoMatchingErrors(t, errmsg, errs) + return + } else { + t.Fatalf("missing expected error %q (0 errors are returned)", errmsg) + } +} + +func TestApexPermittedPackagesRules(t *testing.T) { + testcases := []struct { + name string + expectedError string + bp string + bootJars []string + modulesPackages map[string][]string + }{ + + { + name: "Non-Bootclasspath apex jar not satisfying allowed module packages.", + expectedError: "", + bp: ` + java_library { + name: "bcp_lib1", + srcs: ["lib1/src/*.java"], + permitted_packages: ["foo.bar"], + apex_available: ["myapex"], + sdk_version: "none", + system_modules: "none", + } + java_library { + name: "nonbcp_lib2", + srcs: ["lib2/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["a.b"], + sdk_version: "none", + system_modules: "none", + } + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["bcp_lib1", "nonbcp_lib2"], + }`, + bootJars: []string{"bcp_lib1"}, + modulesPackages: map[string][]string{ + "myapex": []string{ + "foo.bar", + }, + }, + }, + { + name: "Bootclasspath apex jar not satisfying allowed module packages.", + expectedError: `module "bcp_lib2" .* which is restricted because jars that are part of the myapex module may only allow these packages: foo.bar. Please jarjar or move code around.`, + bp: ` + java_library { + name: "bcp_lib1", + srcs: ["lib1/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar"], + sdk_version: "none", + system_modules: "none", + } + java_library { + name: "bcp_lib2", + srcs: ["lib2/src/*.java"], + apex_available: ["myapex"], + permitted_packages: ["foo.bar", "bar.baz"], + sdk_version: "none", + system_modules: "none", + } + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["bcp_lib1", "bcp_lib2"], + } + `, + bootJars: []string{"bcp_lib1", "bcp_lib2"}, + modulesPackages: map[string][]string{ + "myapex": []string{ + "foo.bar", + }, + }, + }, + } + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + rules := createApexPermittedPackagesRules(tc.modulesPackages) + testApexPermittedPackagesRules(t, tc.expectedError, tc.bp, tc.bootJars, rules) + }) + } +} + func TestTestFor(t *testing.T) { ctx, _ := testApex(t, ` apex { @@ -5753,8 +5942,10 @@ func TestApexSet(t *testing.T) { } `, func(fs map[string][]byte, config android.Config) { config.TestProductVariables.Platform_sdk_version = intPtr(30) - config.TestProductVariables.DeviceArch = proptools.StringPtr("arm") - config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm64") + config.Targets[android.Android] = []android.Target{ + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}}, + {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}}, + } }) m := ctx.ModuleForTests("myapex", "android_common") diff --git a/apex/builder.go b/apex/builder.go index 0a1ec3eb3..c5680ad2d 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -63,6 +63,8 @@ func init() { pctx.HostBinToolVariable("jsonmodify", "jsonmodify") pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest") pctx.HostBinToolVariable("extract_apks", "extract_apks") + pctx.HostBinToolVariable("make_f2fs", "make_f2fs") + pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs") } var ( @@ -116,12 +118,12 @@ var ( `--payload_type image ` + `--key ${key} ${opt_flags} ${image_dir} ${out} `, CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}", - "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", + "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}", "${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"}, Rspfile: "${out}.copy_commands", RspfileContent: "${copy_commands}", Description: "APEX ${image_dir} => ${out}", - }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest") + }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type") zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{ Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` + @@ -193,7 +195,7 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, // collect jniLibs. Notice that a.filesInfo is already sorted var jniLibs []string for _, fi := range a.filesInfo { - if fi.isJniLib { + if fi.isJniLib && !android.InList(fi.Stem(), jniLibs) { jniLibs = append(jniLibs, fi.Stem()) } } @@ -284,6 +286,10 @@ func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName st return true }) + for _, fi := range a.filesInfo { + noticeFiles = append(noticeFiles, fi.noticeFiles...) + } + if len(noticeFiles) == 0 { return android.NoticeOutputs{} } @@ -582,6 +588,8 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String()) } + optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string()) + ctx.Build(pctx, android.BuildParams{ Rule: apexRule, Implicits: implicitInputs, @@ -648,7 +656,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { a.container_certificate_file, a.container_private_key_file, } - if ctx.Config().IsEnvTrue("RBE_SIGNAPK") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") { rule = java.SignapkRE args["implicits"] = strings.Join(implicits.Strings(), ",") args["outCommaList"] = a.outputFile.String() @@ -682,7 +690,7 @@ func (a *apexBundle) buildFlattenedApex(ctx android.ModuleContext) { apexBundleName := a.Name() a.outputFile = android.PathForModuleInstall(&factx, "apex", apexBundleName) - if a.installable() && a.GetOverriddenBy() == "" { + if a.installable() { installPath := android.PathForModuleInstall(ctx, "apex", apexBundleName) devicePath := android.InstallPathToOnDevicePath(ctx, installPath) addFlattenedFileContextsInfos(ctx, apexBundleName+":"+devicePath+":"+a.fileContexts.String()) diff --git a/apex/prebuilt.go b/apex/prebuilt.go index d459f8755..37457e921 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -257,6 +257,9 @@ type ApexSet struct { // list of commands to create symlinks for backward compatibility. // these commands will be attached as LOCAL_POST_INSTALL_CMD compatSymlinks []string + + hostRequired []string + postInstallCommands []string } type ApexSetProperties struct { @@ -343,21 +346,43 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { for _, overridden := range a.properties.Overrides { a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...) } + + if ctx.Config().InstallExtraFlattenedApexes() { + // flattened apex should be in /system_ext/apex + flattenedApexDir := android.PathForModuleInstall(&systemExtContext{ctx}, "apex", a.BaseModuleName()) + a.postInstallCommands = append(a.postInstallCommands, + fmt.Sprintf("$(HOST_OUT_EXECUTABLES)/deapexer --debugfs_path $(HOST_OUT_EXECUTABLES)/debugfs extract %s %s", + a.outputApex.String(), + flattenedApexDir.ToMakePath().String(), + )) + a.hostRequired = []string{"deapexer", "debugfs"} + } +} + +type systemExtContext struct { + android.ModuleContext +} + +func (*systemExtContext) SystemExtSpecific() bool { + return true } func (a *ApexSet) AndroidMkEntries() []android.AndroidMkEntries { return []android.AndroidMkEntries{android.AndroidMkEntries{ - Class: "ETC", - OutputFile: android.OptionalPathForPath(a.outputApex), - Include: "$(BUILD_PREBUILT)", + Class: "ETC", + OutputFile: android.OptionalPathForPath(a.outputApex), + Include: "$(BUILD_PREBUILT)", + Host_required: a.hostRequired, ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(entries *android.AndroidMkEntries) { entries.SetString("LOCAL_MODULE_PATH", a.installDir.ToMakePath().String()) entries.SetString("LOCAL_MODULE_STEM", a.installFilename) entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !a.installable()) entries.AddStrings("LOCAL_OVERRIDES_MODULES", a.properties.Overrides...) - if len(a.compatSymlinks) > 0 { - entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(a.compatSymlinks, " && ")) + postInstallCommands := append([]string{}, a.postInstallCommands...) + postInstallCommands = append(postInstallCommands, a.compatSymlinks...) + if len(postInstallCommands) > 0 { + entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(postInstallCommands, " && ")) } }, }, diff --git a/bpf/bpf.go b/bpf/bpf.go index 4cdfb315c..297e13a4f 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -26,7 +26,7 @@ import ( ) func init() { - android.RegisterModuleType("bpf", bpfFactory) + android.RegisterModuleType("bpf", BpfFactory) pctx.Import("android/soong/cc/config") } @@ -43,6 +43,13 @@ var ( "ccCmd", "cFlags") ) +// BpfModule interface is used by the apex package to gather information from a bpf module. +type BpfModule interface { + android.Module + + OutputFiles(tag string) (android.Paths, error) +} + type BpfProperties struct { Srcs []string `android:"path"` Cflags []string @@ -141,7 +148,7 @@ func (bpf *bpf) OutputFiles(tag string) (android.Paths, error) { var _ android.OutputFileProducer = (*bpf)(nil) -func bpfFactory() android.Module { +func BpfFactory() android.Module { module := &bpf{} module.AddProperties(&module.properties) diff --git a/bpf/bpf_test.go b/bpf/bpf_test.go index eeca05771..d06d7d1a5 100644 --- a/bpf/bpf_test.go +++ b/bpf/bpf_test.go @@ -59,7 +59,7 @@ func testConfig(buildDir string, env map[string]string, bp string) android.Confi func testContext(config android.Config) *android.TestContext { ctx := cc.CreateTestContext() - ctx.RegisterModuleType("bpf", bpfFactory) + ctx.RegisterModuleType("bpf", BpfFactory) ctx.Register(config) return ctx diff --git a/cc/androidmk.go b/cc/androidmk.go index 9ed8d8189..380b4e92f 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -167,6 +167,14 @@ func AndroidMkDataPaths(data []android.DataPath) []string { return testFiles } +func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) { + if len(extraTestConfigs) > 0 { + entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { + entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...) + }) + } +} + func androidMkWriteTestData(data []android.DataPath, ctx AndroidMkContext, entries *android.AndroidMkEntries) { testFiles := AndroidMkDataPaths(data) if len(testFiles) > 0 { @@ -369,9 +377,11 @@ func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android. if !BoolDefault(test.Properties.Auto_gen_config, true) { entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true) } + entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...) }) androidMkWriteTestData(test.data, ctx, entries) + androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries) } func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { diff --git a/cc/binary.go b/cc/binary.go index 6769fa778..b3ce5ff1c 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -83,7 +83,7 @@ func binaryHostFactory() android.Module { type binaryDecorator struct { *baseLinker *baseInstaller - stripper + stripper Stripper Properties BinaryLinkerProperties @@ -317,14 +317,14 @@ func (binary *binaryDecorator) link(ctx ModuleContext, } builderFlags := flagsToBuilderFlags(flags) - - if binary.stripper.needsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) + if binary.stripper.NeedsStrip(ctx) { if ctx.Darwin() { - builderFlags.stripUseGnuStrip = true + stripFlags.StripUseGnuStrip = true } strippedOutputFile := outputFile outputFile = android.PathForModuleOut(ctx, "unstripped", fileName) - binary.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags) + binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags) } binary.unstrippedOutputFile = outputFile @@ -333,7 +333,7 @@ func (binary *binaryDecorator) link(ctx ModuleContext, afterPrefixSymbols := outputFile outputFile = android.PathForModuleOut(ctx, "unprefixed", fileName) TransformBinaryPrefixSymbols(ctx, String(binary.Properties.Prefix_symbols), outputFile, - flagsToBuilderFlags(flags), afterPrefixSymbols) + builderFlags, afterPrefixSymbols) } outputFile = maybeInjectBoringSSLHash(ctx, outputFile, binary.Properties.Inject_bssl_hash, fileName) @@ -347,10 +347,10 @@ func (binary *binaryDecorator) link(ctx ModuleContext, versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile) - if binary.stripper.needsStrip(ctx) { + if binary.stripper.NeedsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) binary.distFiles = android.MakeDefaultDistFiles(out) - binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) + binary.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags) } binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile) @@ -445,7 +445,7 @@ func (binary *binaryDecorator) install(ctx ModuleContext, file android.Path) { // The original path becomes a symlink to the corresponding file in the // runtime APEX. translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled - if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() { + if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() { if ctx.Device() && isBionic(ctx.baseModuleName()) { binary.installSymlinkToRuntimeApex(ctx, file) } diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go index 337de55b3..a1abc728a 100644 --- a/cc/binary_sdk_member.go +++ b/cc/binary_sdk_member.go @@ -46,9 +46,13 @@ func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorConte if version == "" { version = LatestStubsVersionFor(mctx.Config(), name) } - mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "version", Variation: version}, - }...), dependencyTag, name) + variations := target.Variations() + if mctx.Device() { + variations = append(variations, + blueprint.Variation{Mutator: "image", Variation: android.CoreVariation}, + blueprint.Variation{Mutator: "version", Variation: version}) + } + mctx.AddFarVariationDependencies(variations, dependencyTag, name) } } } diff --git a/cc/builder.go b/cc/builder.go index 28a573f23..ef653481d 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -69,12 +69,12 @@ var ( &remoteexec.REParams{ Labels: map[string]string{"type": "link", "tool": "clang"}, ExecStrategy: "${config.RECXXLinksExecStrategy}", - Inputs: []string{"${out}.rsp"}, + Inputs: []string{"${out}.rsp", "$implicitInputs"}, RSPFile: "${out}.rsp", OutputFiles: []string{"${out}", "$implicitOutputs"}, ToolchainInputs: []string{"$ldCmd"}, Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"}, - }, []string{"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags"}, []string{"implicitOutputs"}) + }, []string{"ldCmd", "crtBegin", "libFlags", "crtEnd", "ldFlags", "extraLibFlags"}, []string{"implicitInputs", "implicitOutputs"}) partialLd, partialLdRE = remoteexec.StaticRules(pctx, "partialLd", blueprint.RuleParams{ @@ -83,12 +83,13 @@ var ( Command: "$reTemplate$ldCmd -fuse-ld=lld -nostdlib -no-pie -Wl,-r ${in} -o ${out} ${ldFlags}", CommandDeps: []string{"$ldCmd"}, }, &remoteexec.REParams{ - Labels: map[string]string{"type": "link", "tool": "clang"}, - ExecStrategy: "${config.RECXXLinksExecStrategy}", Inputs: []string{"$inCommaList"}, + Labels: map[string]string{"type": "link", "tool": "clang"}, + ExecStrategy: "${config.RECXXLinksExecStrategy}", + Inputs: []string{"$inCommaList", "$implicitInputs"}, OutputFiles: []string{"${out}", "$implicitOutputs"}, ToolchainInputs: []string{"$ldCmd"}, Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXLinksPool}"}, - }, []string{"ldCmd", "ldFlags"}, []string{"inCommaList", "implicitOutputs"}) + }, []string{"ldCmd", "ldFlags"}, []string{"implicitInputs", "inCommaList", "implicitOutputs"}) ar = pctx.AndroidStaticRule("ar", blueprint.RuleParams{ @@ -186,8 +187,8 @@ var ( // OutputFile here is $in for remote-execution since its possible that // clang-tidy modifies the given input file itself and $out refers to the // ".tidy" file generated for ninja-dependency reasons. - OutputFiles: []string{"$in"}, - Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"}, + OutputFiles: []string{"$in"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"}, }, []string{"cFlags", "tidyFlags"}, []string{}) _ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm") @@ -236,12 +237,12 @@ var ( }, &remoteexec.REParams{ Labels: map[string]string{"type": "tool", "name": "abi-linker"}, ExecStrategy: "${config.REAbiLinkerExecStrategy}", - Inputs: []string{"$sAbiLinkerLibs", "${out}.rsp", "$implicits"}, + Inputs: []string{"$sAbiLinkerLibs", "${out}.rsp", "$implicitInputs"}, RSPFile: "${out}.rsp", OutputFiles: []string{"$out"}, ToolchainInputs: []string{"$sAbiLinker"}, Platform: map[string]string{remoteexec.PoolKey: "${config.RECXXPool}"}, - }, []string{"symbolFilter", "arch", "exportedHeaderFlags"}, []string{"implicits"}) + }, []string{"symbolFilter", "arch", "exportedHeaderFlags"}, []string{"implicitInputs"}) _ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/clang-tools/${config.HostPrebuiltTag}/bin/header-abi-diff") @@ -265,9 +266,9 @@ var ( zip = pctx.AndroidStaticRule("zip", blueprint.RuleParams{ - Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp", + Command: "${SoongZipCmd} -o ${out} -C $$OUT_DIR -r ${out}.rsp", CommandDeps: []string{"${SoongZipCmd}"}, - Rspfile: "$out.rsp", + Rspfile: "${out}.rsp", RspfileContent: "$in", }) @@ -349,18 +350,22 @@ type builderFlags struct { groupStaticLibs bool - stripKeepSymbols bool - stripKeepSymbolsList string - stripKeepSymbolsAndDebugFrame bool - stripKeepMiniDebugInfo bool - stripAddGnuDebuglink bool - stripUseGnuStrip bool - proto android.ProtoFlags protoC bool protoOptionsFile bool yacc *YaccProperties + lex *LexProperties +} + +type StripFlags struct { + Toolchain config.Toolchain + StripKeepSymbols bool + StripKeepSymbolsList string + StripKeepSymbolsAndDebugFrame bool + StripKeepMiniDebugInfo bool + StripAddGnuDebuglink bool + StripUseGnuStrip bool } type Objects struct { @@ -579,7 +584,7 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and tidyFiles = append(tidyFiles, tidyFile) rule := clangTidy - if ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") { rule = clangTidyRE } @@ -605,7 +610,7 @@ func TransformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles and sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile) dumpRule := sAbiDump - if ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") { dumpRule = sAbiDumpRE } ctx.Build(pctx, android.BuildParams{ @@ -740,9 +745,10 @@ func TransformObjToDynamicBinary(ctx android.ModuleContext, "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags, "crtEnd": crtEnd.String(), } - if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { rule = ldRE args["implicitOutputs"] = strings.Join(implicitOutputs.Strings(), ",") + args["implicitInputs"] = strings.Join(deps.Strings(), ",") } ctx.Build(pctx, android.BuildParams{ @@ -783,7 +789,7 @@ func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Path "arch": ctx.Arch().ArchType.Name, "exportedHeaderFlags": exportedHeaderFlags, } - if ctx.Config().IsEnvTrue("RBE_ABI_LINKER") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_LINKER") { rule = sAbiLinkRE rbeImplicits := implicits.Strings() for _, p := range strings.Split(exportedHeaderFlags, " ") { @@ -792,7 +798,7 @@ func TransformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Path rbeImplicits = append(rbeImplicits, p[2:]) } } - args["implicits"] = strings.Join(rbeImplicits, ",") + args["implicitInputs"] = strings.Join(rbeImplicits, ",") } ctx.Build(pctx, android.BuildParams{ Rule: rule, @@ -906,9 +912,10 @@ func TransformObjsToObj(ctx android.ModuleContext, objFiles android.Paths, "ldCmd": ldCmd, "ldFlags": flags.globalLdFlags + " " + flags.localLdFlags, } - if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") { rule = partialLdRE args["inCommaList"] = strings.Join(objFiles.Strings(), ",") + args["implicitInputs"] = strings.Join(deps.Strings(), ",") } ctx.Build(pctx, android.BuildParams{ Rule: rule, @@ -939,26 +946,26 @@ func TransformBinaryPrefixSymbols(ctx android.ModuleContext, prefix string, inpu } func TransformStrip(ctx android.ModuleContext, inputFile android.Path, - outputFile android.WritablePath, flags builderFlags) { + outputFile android.WritablePath, flags StripFlags) { - crossCompile := gccCmd(flags.toolchain, "") + crossCompile := gccCmd(flags.Toolchain, "") args := "" - if flags.stripAddGnuDebuglink { + if flags.StripAddGnuDebuglink { args += " --add-gnu-debuglink" } - if flags.stripKeepMiniDebugInfo { + if flags.StripKeepMiniDebugInfo { args += " --keep-mini-debug-info" } - if flags.stripKeepSymbols { + if flags.StripKeepSymbols { args += " --keep-symbols" } - if flags.stripKeepSymbolsList != "" { - args += " -k" + flags.stripKeepSymbolsList + if flags.StripKeepSymbolsList != "" { + args += " -k" + flags.StripKeepSymbolsList } - if flags.stripKeepSymbolsAndDebugFrame { + if flags.StripKeepSymbolsAndDebugFrame { args += " --keep-symbols-and-debug-frame" } - if flags.stripUseGnuStrip { + if flags.StripUseGnuStrip { args += " --use-gnu-strip" } @@ -210,6 +210,7 @@ type Flags struct { protoOptionsFile bool // Whether to look for a .options file next to the .proto Yacc *YaccProperties + Lex *LexProperties } // Properties used to compile all C or C++ modules @@ -279,6 +280,13 @@ type BaseProperties struct { // Set when both SDK and platform variants are exported to Make to trigger renaming the SDK // variant to have a ".sdk" suffix. SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"` + + // Normally Soong uses the directory structure to decide which modules + // should be included (framework) or excluded (non-framework) from the + // vendor snapshot, but this property allows a partner to exclude a + // module normally thought of as a framework module from the vendor + // snapshot. + Exclude_from_vendor_snapshot *bool } type VendorProperties struct { @@ -1107,6 +1115,10 @@ func (c *Module) ExportedGeneratedHeaders() android.Paths { return nil } +func (c *Module) ExcludeFromVendorSnapshot() bool { + return Bool(c.Properties.Exclude_from_vendor_snapshot) +} + func isBionic(name string) bool { switch name { case "libc", "libm", "libdl", "libdl_android", "linker": @@ -2390,7 +2402,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if ccDep.CcLibrary() && !libDepTag.static() { depIsStubs := ccDep.BuildStubs() depHasStubs := VersionVariantAvailable(c) && ccDep.HasStubsVariants() - depInSameApex := android.DirectlyInApex(c.ApexVariationName(), depName) + depInSameApexes := android.DirectlyInAllApexes(c.InApexes(), depName) depInPlatform := !android.DirectlyInAnyApex(ctx, depName) var useThisDep bool @@ -2420,9 +2432,9 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } } else { - // If building for APEX, use stubs only when it is not from - // the same APEX - useThisDep = (depInSameApex != depIsStubs) + // If building for APEX, use stubs when the parent is in any APEX that + // the child is not in. + useThisDep = (depInSameApexes != depIsStubs) } // when to use (unspecified) stubs, check min_sdk_version and choose the right one @@ -2895,6 +2907,16 @@ func (c *Module) TestFor() []string { } } +func (c *Module) UniqueApexVariations() bool { + if u, ok := c.compiler.(interface { + uniqueApexVariations() bool + }); ok { + return u.uniqueApexVariations() + } else { + return false + } +} + // Return true if the module is ever installable. func (c *Module) EverInstallable() bool { return c.installer != nil && diff --git a/cc/cc_test.go b/cc/cc_test.go index 77b5c527b..a4c067772 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -258,7 +258,8 @@ func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string } } -func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { +func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool) { + t.Helper() mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer) if !ok { t.Errorf("%q must have output\n", moduleName) @@ -271,12 +272,27 @@ func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.Tes } snapshotPath := filepath.Join(subDir, snapshotFilename) - out := singleton.Output(snapshotPath) - if out.Input.String() != outputFiles[0].String() { - t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0]) + if include { + out := singleton.Output(snapshotPath) + if out.Input.String() != outputFiles[0].String() { + t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0]) + } + } else { + out := singleton.MaybeOutput(snapshotPath) + if out.Rule != nil { + t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0]) + } } } +func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true) +} + +func checkSnapshotExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false) +} + func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) { t.Helper() assertString(t, params.Rule.String(), android.WriteFile.String()) @@ -930,7 +946,7 @@ func TestDoubleLoadbleDep(t *testing.T) { `) } -func TestVendorSnapshot(t *testing.T) { +func TestVendorSnapshotCapture(t *testing.T) { bp := ` cc_library { name: "libvndk", @@ -1063,6 +1079,215 @@ func TestVendorSnapshot(t *testing.T) { } } +func TestVendorSnapshotUse(t *testing.T) { + frameworkBp := ` + cc_library { + name: "libvndk", + vendor_available: true, + vndk: { + enabled: true, + }, + nocrt: true, + compile_multilib: "64", + } + + cc_library { + name: "libvendor", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + compile_multilib: "64", + } + + cc_binary { + name: "bin", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + compile_multilib: "64", + } +` + + vndkBp := ` + vndk_prebuilt_shared { + name: "libvndk", + version: "BOARD", + target_arch: "arm64", + vendor_available: true, + vndk: { + enabled: true, + }, + arch: { + arm64: { + srcs: ["libvndk.so"], + }, + }, + } +` + + vendorProprietaryBp := ` + cc_library { + name: "libvendor_without_snapshot", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + compile_multilib: "64", + } + + cc_library_shared { + name: "libclient", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + shared_libs: ["libvndk"], + static_libs: ["libvendor", "libvendor_without_snapshot"], + compile_multilib: "64", + } + + cc_binary { + name: "bin_without_snapshot", + vendor: true, + nocrt: true, + no_libcrt: true, + stl: "none", + system_shared_libs: [], + static_libs: ["libvndk"], + compile_multilib: "64", + } + + vendor_snapshot_static { + name: "libvndk", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvndk.a", + }, + }, + } + + vendor_snapshot_shared { + name: "libvendor", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvendor.so", + }, + }, + } + + vendor_snapshot_static { + name: "libvendor", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "libvendor.a", + }, + }, + } + + vendor_snapshot_binary { + name: "bin", + version: "BOARD", + target_arch: "arm64", + vendor: true, + arch: { + arm64: { + src: "bin", + }, + }, + } +` + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "vendor/Android.bp": []byte(vendorProprietaryBp), + "vendor/libvndk.a": nil, + "vendor/libvendor.a": nil, + "vendor/libvendor.so": nil, + "vendor/bin": nil, + "vndk/Android.bp": []byte(vndkBp), + "vndk/libvndk.so": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext() + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared" + staticVariant := "android_vendor.BOARD_arm64_armv8-a_static" + binaryVariant := "android_vendor.BOARD_arm64_armv8-a" + + // libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot + libclientLdRule := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld") + libclientFlags := libclientLdRule.Args["libFlags"] + + for _, input := range [][]string{ + []string{sharedVariant, "libvndk.vndk.BOARD.arm64"}, + []string{staticVariant, "libvendor.vendor_static.BOARD.arm64"}, + []string{staticVariant, "libvendor_without_snapshot"}, + } { + outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */) + if !strings.Contains(libclientFlags, outputPaths[0].String()) { + t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientFlags) + } + } + + // bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64 + binWithoutSnapshotLdRule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld") + binWithoutSnapshotFlags := binWithoutSnapshotLdRule.Args["libFlags"] + libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"}) + if !strings.Contains(binWithoutSnapshotFlags, libVndkStaticOutputPaths[0].String()) { + t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v", + libVndkStaticOutputPaths[0], binWithoutSnapshotFlags) + } + + // libvendor.so is installed by libvendor.vendor_shared.BOARD.arm64 + ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so") + + // libvendor_without_snapshot.so is installed by libvendor_without_snapshot + ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so") + + // bin is installed by bin.vendor_binary.BOARD.arm64 + ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin") + + // bin_without_snapshot is installed by bin_without_snapshot + ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot") + + // libvendor and bin don't have vendor.BOARD variant + libvendorVariants := ctx.ModuleVariantsForTests("libvendor") + if inList(sharedVariant, libvendorVariants) { + t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant) + } + + binVariants := ctx.ModuleVariantsForTests("bin") + if inList(binaryVariant, binVariants) { + t.Errorf("bin must not have variant %#v, but it does", sharedVariant) + } +} + func TestVendorSnapshotSanitizer(t *testing.T) { bp := ` vendor_snapshot_static { @@ -1096,6 +1321,203 @@ func TestVendorSnapshotSanitizer(t *testing.T) { assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a") } +func assertExcludeFromVendorSnapshotIs(t *testing.T, c *Module, expected bool) { + t.Helper() + if c.ExcludeFromVendorSnapshot() != expected { + t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", c.String(), expected) + } +} + +func TestVendorSnapshotExclude(t *testing.T) { + + // This test verifies that the exclude_from_vendor_snapshot property + // makes its way from the Android.bp source file into the module data + // structure. It also verifies that modules are correctly included or + // excluded in the vendor snapshot based on their path (framework or + // vendor) and the exclude_from_vendor_snapshot property. + + frameworkBp := ` + cc_library_shared { + name: "libinclude", + srcs: ["src/include.cpp"], + vendor_available: true, + } + cc_library_shared { + name: "libexclude", + srcs: ["src/exclude.cpp"], + vendor: true, + exclude_from_vendor_snapshot: true, + } + ` + + vendorProprietaryBp := ` + cc_library_shared { + name: "libvendor", + srcs: ["vendor.cpp"], + vendor: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "framework/include.cpp": nil, + "framework/exclude.cpp": nil, + "device/Android.bp": []byte(vendorProprietaryBp), + "device/vendor.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext() + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + // Test an include and exclude framework module. + assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", coreVariant).Module().(*Module), false) + assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", vendorVariant).Module().(*Module), false) + assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libexclude", vendorVariant).Module().(*Module), true) + + // A vendor module is excluded, but by its path, not the + // exclude_from_vendor_snapshot property. + assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libvendor", vendorVariant).Module().(*Module), false) + + // Verify the content of the vendor snapshot. + + snapshotDir := "vendor-snapshot" + snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") + + var includeJsonFiles []string + var excludeJsonFiles []string + + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + []string{"arm", "armv7-a-neon"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + + // Included modules + checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) + + // Excluded modules + checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) + checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json")) + } + + // Verify that each json file for an included module has a rule. + for _, jsonFile := range includeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("include json file %q not found", jsonFile) + } + } + + // Verify that each json file for an excluded module has no rule. + for _, jsonFile := range excludeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil { + t.Errorf("exclude json file %q found", jsonFile) + } + } +} + +func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) { + + // This test verifies that using the exclude_from_vendor_snapshot + // property on a module in a vendor proprietary path generates an + // error. These modules are already excluded, so we prohibit using the + // property in this way, which could add to confusion. + + vendorProprietaryBp := ` + cc_library_shared { + name: "libvendor", + srcs: ["vendor.cpp"], + vendor: true, + exclude_from_vendor_snapshot: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "device/Android.bp": []byte(vendorProprietaryBp), + "device/vendor.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext() + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"}) + android.FailIfErrored(t, errs) + + _, errs = ctx.PrepareBuildActions(config) + android.CheckErrorsAgainstExpectations(t, errs, []string{ + `module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, + `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`, + }) +} + +func TestVendorSnapshotExcludeWithVendorAvailable(t *testing.T) { + + // This test verifies that using the exclude_from_vendor_snapshot + // property on a module that is vendor available generates an error. A + // vendor available module must be captured in the vendor snapshot and + // must not built from source when building the vendor image against + // the vendor snapshot. + + frameworkBp := ` + cc_library_shared { + name: "libinclude", + srcs: ["src/include.cpp"], + vendor_available: true, + exclude_from_vendor_snapshot: true, + } + ` + + depsBp := GatherRequiredDepsForTest(android.Android) + + mockFS := map[string][]byte{ + "deps/Android.bp": []byte(depsBp), + "framework/Android.bp": []byte(frameworkBp), + "framework/include.cpp": nil, + } + + config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config.TestProductVariables.DeviceVndkVersion = StringPtr("current") + config.TestProductVariables.Platform_vndk_version = StringPtr("VER") + ctx := CreateTestContext() + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp"}) + android.FailIfErrored(t, errs) + + _, errs = ctx.PrepareBuildActions(config) + android.CheckErrorsAgainstExpectations(t, errs, []string{ + `module "libinclude\{.+,image:,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:vendor.+,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + `module "libinclude\{.+,image:vendor.+,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`, + }) +} + func TestDoubleLoadableDepError(t *testing.T) { // Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib. testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", ` diff --git a/cc/compiler.go b/cc/compiler.go index 3737f8a0e..f74582004 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -111,6 +111,7 @@ type BaseCompilerProperties struct { Gnu_extensions *bool Yacc *YaccProperties + Lex *LexProperties Aidl struct { // list of directories that will be added to the aidl include paths. @@ -189,8 +190,14 @@ type BaseCompilerProperties struct { // Build and link with OpenMP Openmp *bool `android:"arch_variant"` + // Deprecated. // Adds __ANDROID_APEX_<APEX_MODULE_NAME>__ macro defined for apex variants in addition to __ANDROID_APEX__ Use_apex_name_macro *bool + + // Adds two macros for apex variants in addition to __ANDROID_APEX__ + // * __ANDROID_APEX_COM_ANDROID_FOO__ + // * __ANDROID_APEX_NAME__="com.android.foo" + UseApexNameMacro bool `blueprint:"mutated"` } func NewBaseCompiler() *baseCompiler { @@ -254,6 +261,10 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { return deps } +func (compiler *baseCompiler) useApexNameMacro() bool { + return Bool(compiler.Properties.Use_apex_name_macro) || compiler.Properties.UseApexNameMacro +} + // Return true if the module is in the WarningAllowedProjects. func warningsAreAllowed(subdir string) bool { subdir += "/" @@ -289,6 +300,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Local.YasmFlags = append(flags.Local.YasmFlags, esc(compiler.Properties.Asflags)...) flags.Yacc = compiler.Properties.Yacc + flags.Lex = compiler.Properties.Lex // Include dir cflags localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs) @@ -337,8 +349,9 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps if ctx.apexVariationName() != "" { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX__") - if Bool(compiler.Properties.Use_apex_name_macro) { + if compiler.useApexNameMacro() { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexVariationName())+"__") + flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_NAME__='\""+ctx.apexVariationName()+"\"'") } if ctx.Device() { flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion())) @@ -560,10 +573,16 @@ func (compiler *baseCompiler) hasSrcExt(ext string) bool { return false } +func (compiler *baseCompiler) uniqueApexVariations() bool { + return compiler.useApexNameMacro() +} + +var invalidDefineCharRegex = regexp.MustCompile("[^a-zA-Z0-9_]") + // makeDefineString transforms a name of an APEX module into a value to be used as value for C define // For example, com.android.foo => COM_ANDROID_FOO func makeDefineString(name string) string { - return strings.ReplaceAll(strings.ToUpper(name), ".", "_") + return invalidDefineCharRegex.ReplaceAllString(strings.ToUpper(name), "_") } var gnuToCReplacer = strings.NewReplacer("gnu", "c") diff --git a/cc/config/Android.bp b/cc/config/Android.bp index 6275064f5..ce4bdfb50 100644 --- a/cc/config/Android.bp +++ b/cc/config/Android.bp @@ -23,6 +23,8 @@ bootstrap_go_package { "x86_linux_host.go", "x86_linux_bionic_host.go", "x86_windows_host.go", + + "arm64_linux_host.go", ], testSrcs: [ "tidy_test.go", diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go new file mode 100644 index 000000000..74642c2cf --- /dev/null +++ b/cc/config/arm64_linux_host.go @@ -0,0 +1,94 @@ +// 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 config + +import ( + "android/soong/android" + "strings" +) + +var ( + // This is a host toolchain but flags for device toolchain are required + // as the flags are actually for Bionic-based builds. + linuxCrossCflags = ClangFilterUnknownCflags(append(deviceGlobalCflags, + // clang by default enables PIC when the clang triple is set to *-android. + // See toolchain/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp#920. + // However, for this host target, we don't set "-android" to avoid __ANDROID__ macro + // which stands for "Android device target". Keeping PIC on is required because + // many modules we have (e.g. Bionic) assume PIC. + "-fpic", + )) + + linuxCrossLdflags = ClangFilterUnknownCflags([]string{ + "-Wl,-z,noexecstack", + "-Wl,-z,relro", + "-Wl,-z,now", + "-Wl,--build-id=md5", + "-Wl,--warn-shared-textrel", + "-Wl,--fatal-warnings", + "-Wl,--hash-style=gnu", + "-Wl,--no-undefined-version", + }) +) + +func init() { + pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " ")) + pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " ")) +} + +// toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android +// target. The overridden methods below show the differences. +type toolchainLinuxArm64 struct { + toolchainArm64 +} + +func (toolchainLinuxArm64) ClangTriple() string { + // Note the absence of "-android" suffix. The compiler won't define __ANDROID__ + return "aarch64-linux" +} + +func (toolchainLinuxArm64) ClangCflags() string { + // The inherited flags + extra flags + return "${config.Arm64ClangCflags} ${config.LinuxBionicArm64Cflags}" +} + +func linuxArm64ToolchainFactory(arch android.Arch) Toolchain { + archVariant := "armv8-a" // for host, default to armv8-a + toolchainClangCflags := []string{arm64ClangArchVariantCflagsVar[archVariant]} + + // We don't specify CPU architecture for host. Conservatively assume + // the host CPU needs the fix + extraLdflags := "-Wl,--fix-cortex-a53-843419" + + ret := toolchainLinuxArm64{} + + // add the extra ld and lld flags + ret.toolchainArm64.ldflags = strings.Join([]string{ + "${config.Arm64Ldflags}", + "${config.LinuxBionicArm64Ldflags}", + extraLdflags, + }, " ") + ret.toolchainArm64.lldflags = strings.Join([]string{ + "${config.Arm64Lldflags}", + "${config.LinuxBionicArm64Ldflags}", + extraLdflags, + }, " ") + ret.toolchainArm64.toolchainClangCflags = strings.Join(toolchainClangCflags, " ") + return &ret +} + +func init() { + registerToolchainFactory(android.LinuxBionic, android.Arm64, linuxArm64ToolchainFactory) +} diff --git a/cc/config/clang.go b/cc/config/clang.go index 24dc6b932..7db405c2e 100644 --- a/cc/config/clang.go +++ b/cc/config/clang.go @@ -15,6 +15,7 @@ package config import ( + "android/soong/android" "sort" "strings" ) @@ -88,6 +89,12 @@ var ClangUnknownLldflags = sorted([]string{ var ClangLibToolingUnknownCflags = sorted([]string{}) +// List of tidy checks that should be disabled globally. When the compiler is +// updated, some checks enabled by this module may be disabled if they have +// become more strict, or if they are a new match for a wildcard group like +// `modernize-*`. +var ClangTidyDisableChecks = []string{} + func init() { pctx.StaticVariable("ClangExtraCflags", strings.Join([]string{ "-D__compiler_offsetof=__builtin_offsetof", @@ -202,25 +209,34 @@ func init() { } func ClangFilterUnknownCflags(cflags []string) []string { - ret := make([]string, 0, len(cflags)) - for _, f := range cflags { - if !inListSorted(f, ClangUnknownCflags) { - ret = append(ret, f) + result, _ := android.FilterList(cflags, ClangUnknownCflags) + return result +} + +func clangTidyNegateChecks(checks []string) []string { + ret := make([]string, 0, len(checks)) + for _, c := range checks { + if strings.HasPrefix(c, "-") { + ret = append(ret, c) + } else { + ret = append(ret, "-"+c) } } - return ret } -func ClangFilterUnknownLldflags(lldflags []string) []string { - ret := make([]string, 0, len(lldflags)) - for _, f := range lldflags { - if !inListSorted(f, ClangUnknownLldflags) { - ret = append(ret, f) - } - } +func ClangRewriteTidyChecks(checks []string) []string { + checks = append(checks, clangTidyNegateChecks(ClangTidyDisableChecks)...) + // clang-tidy does not allow later arguments to override earlier arguments, + // so if we just disabled an argument that was explicitly enabled we must + // remove the enabling argument from the list. + result, _ := android.FilterList(checks, ClangTidyDisableChecks) + return result +} - return ret +func ClangFilterUnknownLldflags(lldflags []string) []string { + result, _ := android.FilterList(lldflags, ClangUnknownLldflags) + return result } func inListSorted(s string, list []string) bool { diff --git a/cc/config/vndk.go b/cc/config/vndk.go index 54f693e0b..6f2e80741 100644 --- a/cc/config/vndk.go +++ b/cc/config/vndk.go @@ -18,10 +18,12 @@ package config // For these libraries, the vendor variants must be installed even if the device // has VndkUseCoreVariant set. var VndkMustUseVendorVariantList = []string{ + "android.hardware.automotive.occupant_awareness-ndk_platform", "android.hardware.light-ndk_platform", "android.hardware.identity-ndk_platform", "android.hardware.nfc@1.2", "android.hardware.power-ndk_platform", + "android.hardware.rebootescrow-ndk_platform", "android.hardware.vibrator-ndk_platform", "libbinder", "libcrypto", diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go index cd0a50837..b5b555322 100644 --- a/cc/config/x86_windows_host.go +++ b/cc/config/x86_windows_host.go @@ -49,7 +49,11 @@ var ( windowsClangCppflags = []string{} - windowsX86ClangCppflags = []string{} + windowsX86ClangCppflags = []string{ + // Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj + // exception model for 32-bit. + "-fsjlj-exceptions", + } windowsX8664ClangCppflags = []string{} diff --git a/cc/fuzz.go b/cc/fuzz.go index 58c1888ad..529541859 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -402,7 +402,7 @@ func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { command := builder.Command().BuiltTool(ctx, "soong_zip"). Flag("-j"). FlagWithOutput("-o ", corpusZip) - command.FlagWithRspFileInputList("-l ", fuzzModule.corpus) + command.FlagWithRspFileInputList("-r ", fuzzModule.corpus) files = append(files, fileToZip{corpusZip, ""}) } @@ -34,9 +34,9 @@ func init() { var ( lex = pctx.AndroidStaticRule("lex", blueprint.RuleParams{ - Command: "M4=$m4Cmd $lexCmd -o$out $in", + Command: "M4=$m4Cmd $lexCmd $flags -o$out $in", CommandDeps: []string{"$lexCmd", "$m4Cmd"}, - }) + }, "flags") sysprop = pctx.AndroidStaticRule("sysprop", blueprint.RuleParams{ @@ -153,12 +153,23 @@ func genAidl(ctx android.ModuleContext, rule *android.RuleBuilder, aidlFile andr } } -func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath) { +type LexProperties struct { + // list of module-specific flags that will be used for .l and .ll compiles + Flags []string +} + +func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath, props *LexProperties) { + var flags []string + if props != nil { + flags = props.Flags + } + flagsString := strings.Join(flags[:], " ") ctx.Build(pctx, android.BuildParams{ Rule: lex, Description: "lex " + lexFile.Rel(), Output: outFile, Input: lexFile, + Args: map[string]string{"flags": flagsString}, }) } @@ -235,11 +246,11 @@ func genSources(ctx android.ModuleContext, srcFiles android.Paths, case ".l": cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c") srcFiles[i] = cFile - genLex(ctx, srcFile, cFile) + genLex(ctx, srcFile, cFile, buildFlags.lex) case ".ll": cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp") srcFiles[i] = cppFile - genLex(ctx, srcFile, cppFile) + genLex(ctx, srcFile, cppFile, buildFlags.lex) case ".proto": ccFile, headerFile := genProto(ctx, srcFile, buildFlags) srcFiles[i] = ccFile diff --git a/cc/genrule.go b/cc/genrule.go index 66d178456..cce4a83d3 100644 --- a/cc/genrule.go +++ b/cc/genrule.go @@ -84,7 +84,7 @@ func (g *GenruleExtraProperties) ExtraImageVariations(ctx android.BaseModuleCont // If not, we assume modules under proprietary paths are compatible for // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is // PLATFORM_VNDK_VERSION. - if vndkVersion == "current" || !isVendorProprietaryPath(ctx.ModuleDir()) { + if vndkVersion == "current" || !isVendorProprietaryModule(ctx) { variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion()) } else { variants = append(variants, VendorVariationPrefix+vndkVersion) diff --git a/cc/image.go b/cc/image.go index 4daed7c00..ea6f5675c 100644 --- a/cc/image.go +++ b/cc/image.go @@ -223,7 +223,7 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { // We assume that modules under proprietary paths are compatible for // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or // PLATFORM_VNDK_VERSION. - if isVendorProprietaryPath(mctx.ModuleDir()) { + if isVendorProprietaryModule(mctx) { vendorVariants = append(vendorVariants, boardVndkVersion) } else { vendorVariants = append(vendorVariants, platformVndkVersion) @@ -249,7 +249,7 @@ func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) { platformVndkVersion, boardVndkVersion, ) - } else if isVendorProprietaryPath(mctx.ModuleDir()) { + } else if isVendorProprietaryModule(mctx) { vendorVariants = append(vendorVariants, boardVndkVersion) } else { vendorVariants = append(vendorVariants, platformVndkVersion) diff --git a/cc/library.go b/cc/library.go index 1c2b1ee88..92853b5d3 100644 --- a/cc/library.go +++ b/cc/library.go @@ -336,7 +336,7 @@ type libraryDecorator struct { tocFile android.OptionalPath flagExporter - stripper + stripper Stripper // If we're used as a whole_static_lib, our missing dependencies need // to be given @@ -955,13 +955,14 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, library.tocFile = android.OptionalPathForPath(tocFile) TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags) - if library.stripper.needsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) + if library.stripper.NeedsStrip(ctx) { if ctx.Darwin() { - builderFlags.stripUseGnuStrip = true + stripFlags.StripUseGnuStrip = true } strippedOutputFile := outputFile outputFile = android.PathForModuleOut(ctx, "unstripped", fileName) - library.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags) + library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags) } library.unstrippedOutputFile = outputFile @@ -976,10 +977,10 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName) library.distFile = versionedOutputFile - if library.stripper.needsStrip(ctx) { + if library.stripper.NeedsStrip(ctx) { out := android.PathForModuleOut(ctx, "versioned-stripped", fileName) library.distFile = out - library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags) + library.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags) } library.injectVersionSymbol(ctx, outputFile, versionedOutputFile) @@ -1027,6 +1028,10 @@ func (library *libraryDecorator) unstrippedOutputFilePath() android.Path { return library.unstrippedOutputFile } +func (library *libraryDecorator) disableStripping() { + library.stripper.StripProperties.Strip.None = BoolPtr(true) +} + func (library *libraryDecorator) nativeCoverage() bool { if library.header() || library.buildStubs() { return false diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index cff00b668..ecfdc9977 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -82,18 +82,19 @@ func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorCont if version == "" { version = LatestStubsVersionFor(mctx.Config(), name) } + variations := target.Variations() + if mctx.Device() { + variations = append(variations, + blueprint.Variation{Mutator: "image", Variation: android.CoreVariation}, + blueprint.Variation{Mutator: "version", Variation: version}) + } if mt.linkTypes == nil { - mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "image", Variation: android.CoreVariation}, - {Mutator: "version", Variation: version}, - }...), dependencyTag, name) + mctx.AddFarVariationDependencies(variations, dependencyTag, name) } else { for _, linkType := range mt.linkTypes { - mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{ - {Mutator: "image", Variation: android.CoreVariation}, - {Mutator: "link", Variation: linkType}, - {Mutator: "version", Variation: version}, - }...), dependencyTag, name) + libVariations := append(variations, + blueprint.Variation{Mutator: "link", Variation: linkType}) + mctx.AddFarVariationDependencies(libVariations, dependencyTag, name) } } } @@ -118,6 +119,14 @@ func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, ccModule := member.Variants()[0].(*Module) + if proptools.Bool(ccModule.Properties.Recovery_available) { + pbm.AddProperty("recovery_available", true) + } + + if proptools.Bool(ccModule.VendorProperties.Vendor_available) { + pbm.AddProperty("vendor_available", true) + } + sdkVersion := ccModule.SdkVersion() if sdkVersion != "" { pbm.AddProperty("sdk_version", sdkVersion) @@ -212,6 +221,11 @@ var includeDirProperties = []includeDirsProperty{ // Add properties that may, or may not, be arch specific. func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) { + if libInfo.SanitizeNever { + sanitizeSet := outputProperties.AddPropertySet("sanitize") + sanitizeSet.AddProperty("never", true) + } + // Copy the generated library to the snapshot and add a reference to it in the .bp module. if libInfo.outputFile != nil { nativeLibraryPath := nativeLibraryPathFor(libInfo) @@ -277,8 +291,8 @@ func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, b } // Add the collated include dir properties to the output. - for property, dirs := range includeDirs { - outputProperties.AddProperty(property, dirs) + for _, property := range android.SortedStringKeys(includeDirs) { + outputProperties.AddProperty(property, includeDirs[property]) } if len(libInfo.StubsVersion) > 0 { @@ -359,6 +373,9 @@ type nativeLibInfoProperties struct { // not vary by arch so cannot be android specific. StubsVersion string `sdk:"ignored-on-host"` + // Value of SanitizeProperties.Sanitize.Never. Needs to be propagated for CRT objects. + SanitizeNever bool `android:"arch_variant"` + // outputFile is not exported as it is always arch specific. outputFile android.Path } @@ -405,6 +422,10 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte if ccModule.HasStubsVariants() { p.StubsVersion = ccModule.StubsVersion() } + + if ccModule.sanitize != nil && proptools.Bool(ccModule.sanitize.Properties.Sanitize.Never) { + p.SanitizeNever = true + } } func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path { diff --git a/cc/llndk_library.go b/cc/llndk_library.go index 71c92042a..b3f9d6177 100644 --- a/cc/llndk_library.go +++ b/cc/llndk_library.go @@ -179,7 +179,7 @@ func NewLLndkStubLibrary() *Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() stub := &llndkStubDecorator{ libraryDecorator: library, diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 58e742e5f..fe3efc01e 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -405,7 +405,7 @@ func newStubLibrary() *Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() stub := &stubDecorator{ libraryDecorator: library, @@ -290,17 +290,16 @@ func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { // Add flags to profile this module based on its profile_kind if props.ShouldProfileModule && props.isInstrumentation() { - props.addInstrumentationProfileGatherFlags(ctx, flags) // Instrumentation PGO use and gather flags cannot coexist. - return flags + return props.addInstrumentationProfileGatherFlags(ctx, flags) } else if props.ShouldProfileModule && props.isSampling() { - props.addSamplingProfileGatherFlags(ctx, flags) + flags = props.addSamplingProfileGatherFlags(ctx, flags) } else if ctx.DeviceConfig().SamplingPGO() { - props.addSamplingProfileGatherFlags(ctx, flags) + flags = props.addSamplingProfileGatherFlags(ctx, flags) } if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { - props.addProfileUseFlags(ctx, flags) + flags = props.addProfileUseFlags(ctx, flags) } return flags diff --git a/cc/prebuilt.go b/cc/prebuilt.go index baf43ce0f..1ee096e18 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -125,9 +125,10 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, outputFile := android.PathForModuleOut(ctx, libName) var implicits android.Paths - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) stripped := android.PathForModuleOut(ctx, "stripped", libName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -323,35 +324,68 @@ func prebuiltObjectFactory() android.Module { type prebuiltBinaryLinker struct { *binaryDecorator prebuiltLinker + + toolPath android.OptionalPath } var _ prebuiltLinkerInterface = (*prebuiltBinaryLinker)(nil) +func (p *prebuiltBinaryLinker) hostToolPath() android.OptionalPath { + return p.toolPath +} + func (p *prebuiltBinaryLinker) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { // TODO(ccross): verify shared library dependencies if len(p.properties.Srcs) > 0 { - builderFlags := flagsToBuilderFlags(flags) - fileName := p.getStem(ctx) + flags.Toolchain.ExecutableSuffix() in := p.Prebuilt.SingleSourcePath(ctx) - + outputFile := android.PathForModuleOut(ctx, fileName) p.unstrippedOutputFile = in - if p.needsStrip(ctx) { - stripped := android.PathForModuleOut(ctx, "stripped", fileName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) - in = stripped - } + if ctx.Host() { + // Host binaries are symlinked to their prebuilt source locations. That + // way they are executed directly from there so the linker resolves their + // shared library dependencies relative to that location (using + // $ORIGIN/../lib(64):$ORIGIN/lib(64) as RUNPATH). This way the prebuilt + // repository can supply the expected versions of the shared libraries + // without interference from what is in the out tree. + + // These shared lib paths may point to copies of the libs in + // .intermediates, which isn't where the binary will load them from, but + // it's fine for dependency tracking. If a library dependency is updated, + // the symlink will get a new timestamp, along with any installed symlinks + // handled in make. + sharedLibPaths := deps.EarlySharedLibs + sharedLibPaths = append(sharedLibPaths, deps.SharedLibs...) + sharedLibPaths = append(sharedLibPaths, deps.LateSharedLibs...) - // Copy binaries to a name matching the final installed name - outputFile := android.PathForModuleOut(ctx, fileName) - ctx.Build(pctx, android.BuildParams{ - Rule: android.CpExecutable, - Description: "prebuilt", - Output: outputFile, - Input: in, - }) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Symlink, + Output: outputFile, + Input: in, + Implicits: sharedLibPaths, + Args: map[string]string{ + "fromPath": "$$PWD/" + in.String(), + }, + }) + + p.toolPath = android.OptionalPathForPath(outputFile) + } else { + if p.stripper.NeedsStrip(ctx) { + stripped := android.PathForModuleOut(ctx, "stripped", fileName) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, flagsToStripFlags(flags)) + in = stripped + } + + // Copy binaries to a name matching the final installed name + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpExecutable, + Description: "prebuilt", + Output: outputFile, + Input: in, + }) + } return outputFile } @@ -378,6 +412,7 @@ func NewPrebuiltBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecor binaryDecorator: binary, } module.linker = prebuilt + module.installer = prebuilt module.AddProperties(&prebuilt.properties) diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index adb44bd71..52416ac3b 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -15,6 +15,7 @@ package cc import ( + "path/filepath" "testing" "android/soong/android" @@ -271,3 +272,52 @@ func TestPrebuiltLibrarySharedStem(t *testing.T) { shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().Path().Base(), "libbar.so") } + +func TestPrebuiltSymlinkedHostBinary(t *testing.T) { + if android.BuildOs != android.Linux { + t.Skipf("Skipping host prebuilt testing that is only supported on %s not %s", android.Linux, android.BuildOs) + } + + ctx := testPrebuilt(t, ` + cc_prebuilt_library_shared { + name: "libfoo", + device_supported: false, + host_supported: true, + target: { + linux_glibc_x86_64: { + srcs: ["linux_glibc_x86_64/lib64/libfoo.so"], + }, + }, + } + + cc_prebuilt_binary { + name: "foo", + device_supported: false, + host_supported: true, + shared_libs: ["libfoo"], + target: { + linux_glibc_x86_64: { + srcs: ["linux_glibc_x86_64/bin/foo"], + }, + }, + } + `, map[string][]byte{ + "libfoo.so": nil, + "foo": nil, + }) + + fooRule := ctx.ModuleForTests("foo", "linux_glibc_x86_64").Rule("Symlink") + assertString(t, fooRule.Output.String(), + filepath.Join(buildDir, ".intermediates/foo/linux_glibc_x86_64/foo")) + assertString(t, fooRule.Args["fromPath"], "$$PWD/linux_glibc_x86_64/bin/foo") + + var libfooDep android.Path + for _, dep := range fooRule.Implicits { + if dep.Base() == "libfoo.so" { + libfooDep = dep + break + } + } + assertString(t, libfooDep.String(), + filepath.Join(buildDir, ".intermediates/libfoo/linux_glibc_x86_64_shared/libfoo.so")) +} diff --git a/cc/sanitize.go b/cc/sanitize.go index 2243082ad..174dcfea5 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -48,6 +48,10 @@ var ( // higher number of "optimized out" stack variables. // b/112437883. "-mllvm", "-instcombine-lower-dbg-declare=0", + // TODO(b/159343917): HWASan and GlobalISel don't play nicely, and + // GlobalISel is the default at -O0 on aarch64. + "-mllvm", "--aarch64-enable-global-isel-at-O=-1", + "-mllvm", "-fast-isel=false", } cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso", @@ -738,7 +742,7 @@ func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool { // as vendor snapshot. Such modules must create both cfi and non-cfi variants, // except for ones which explicitly disable cfi. func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool { - if isVendorProprietaryPath(mctx.ModuleDir()) { + if isVendorProprietaryModule(mctx) { return false } @@ -1011,10 +1015,12 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { // static executable gets static runtime libs depTag := libraryDependencyTag{Kind: staticLibraryDependency} - mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{ - {Mutator: "link", Variation: "static"}, - c.ImageVariation(), - }...), depTag, deps...) + variations := append(mctx.Target().Variations(), + blueprint.Variation{Mutator: "link", Variation: "static"}) + if c.Device() { + variations = append(variations, c.ImageVariation()) + } + mctx.AddFarVariationDependencies(variations, depTag, deps...) } else if !c.static() && !c.header() { // If we're using snapshots and in vendor, redirect to snapshot whenever possible if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() { @@ -1026,10 +1032,12 @@ func sanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { // dynamic executable and shared libs get shared runtime libs depTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: earlyLibraryDependency} - mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{ - {Mutator: "link", Variation: "shared"}, - c.ImageVariation(), - }...), depTag, runtimeLibrary) + variations := append(mctx.Target().Variations(), + blueprint.Variation{Mutator: "link", Variation: "shared"}) + if c.Device() { + variations = append(variations, c.ImageVariation()) + } + mctx.AddFarVariationDependencies(variations, depTag, runtimeLibrary) } // static lib does not have dependency to the runtime library. The // dependency will be added to the executables or shared libs using diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go index 4012def52..f27d166f4 100644 --- a/cc/snapshot_utils.go +++ b/cc/snapshot_utils.go @@ -61,7 +61,7 @@ func (s *snapshotMap) get(name string, arch android.ArchType) (snapshot string, func isSnapshotAware(ctx android.ModuleContext, m *Module) bool { if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m); ok { return ctx.Config().VndkSnapshotBuildArtifacts() - } else if isVendorSnapshotModule(m, ctx.ModuleDir()) { + } else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir())) { return true } return false @@ -239,11 +239,6 @@ func (stl *stl) flags(ctx ModuleContext, flags Flags) Flags { flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++") flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++") if ctx.Windows() { - // Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj - // exception model for 32-bit. - if ctx.Arch().ArchType == android.X86 { - flags.Local.CppFlags = append(flags.Local.CppFlags, "-fsjlj-exceptions") - } flags.Local.CppFlags = append(flags.Local.CppFlags, // Disable visiblity annotations since we're using static // libc++. diff --git a/cc/strip.go b/cc/strip.go index 7e560ec9c..18150dc8d 100644 --- a/cc/strip.go +++ b/cc/strip.go @@ -30,42 +30,42 @@ type StripProperties struct { } `android:"arch_variant"` } -type stripper struct { +type Stripper struct { StripProperties StripProperties } -func (stripper *stripper) needsStrip(ctx ModuleContext) bool { +func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool { // TODO(ccross): enable host stripping when embedded in make? Make never had support for stripping host binaries. - return (!ctx.Config().EmbeddedInMake() || ctx.Device()) && !Bool(stripper.StripProperties.Strip.None) + return (!actx.Config().EmbeddedInMake() || actx.Device()) && !Bool(stripper.StripProperties.Strip.None) } -func (stripper *stripper) strip(ctx ModuleContext, in android.Path, out android.ModuleOutPath, - flags builderFlags, isStaticLib bool) { - if ctx.Darwin() { - TransformDarwinStrip(ctx, in, out) +func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath, + flags StripFlags, isStaticLib bool) { + if actx.Darwin() { + TransformDarwinStrip(actx, in, out) } else { if Bool(stripper.StripProperties.Strip.Keep_symbols) { - flags.stripKeepSymbols = true + flags.StripKeepSymbols = true } else if Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) { - flags.stripKeepSymbolsAndDebugFrame = true + flags.StripKeepSymbolsAndDebugFrame = true } else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 { - flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",") + flags.StripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",") } else if !Bool(stripper.StripProperties.Strip.All) { - flags.stripKeepMiniDebugInfo = true + flags.StripKeepMiniDebugInfo = true } - if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo && !isStaticLib { - flags.stripAddGnuDebuglink = true + if actx.Config().Debuggable() && !flags.StripKeepMiniDebugInfo && !isStaticLib { + flags.StripAddGnuDebuglink = true } - TransformStrip(ctx, in, out, flags) + TransformStrip(actx, in, out, flags) } } -func (stripper *stripper) stripExecutableOrSharedLib(ctx ModuleContext, in android.Path, - out android.ModuleOutPath, flags builderFlags) { - stripper.strip(ctx, in, out, flags, false) +func (stripper *Stripper) StripExecutableOrSharedLib(actx android.ModuleContext, in android.Path, + out android.ModuleOutPath, flags StripFlags) { + stripper.strip(actx, in, out, flags, false) } -func (stripper *stripper) stripStaticLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath, - flags builderFlags) { - stripper.strip(ctx, in, out, flags, true) +func (stripper *Stripper) StripStaticLib(actx android.ModuleContext, in android.Path, out android.ModuleOutPath, + flags StripFlags) { + stripper.strip(actx, in, out, flags, true) } diff --git a/cc/test.go b/cc/test.go index 9b6864a4e..619dc4d00 100644 --- a/cc/test.go +++ b/cc/test.go @@ -40,8 +40,12 @@ type TestProperties struct { type TestOptions struct { // The UID that you want to run the test as on a device. Run_test_as *string + // A list of free-formed strings without spaces that categorize the test. Test_suite_tag []string + + // a list of extra test configuration files that should be installed with the module. + Extra_test_configs []string `android:"path,arch_variant"` } type TestBinaryProperties struct { @@ -219,6 +223,7 @@ func TestPerSrcMutator(mctx android.BottomUpMutatorContext) { tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src) mctx.AddInterVariantDependency(testPerSrcDepTag, all_tests, tests[i]) } + mctx.AliasVariation("") } } } @@ -309,9 +314,10 @@ type testBinary struct { testDecorator *binaryDecorator *baseCompiler - Properties TestBinaryProperties - data []android.DataPath - testConfig android.Path + Properties TestBinaryProperties + data []android.DataPath + testConfig android.Path + extraTestConfigs android.Paths } func (test *testBinary) linkerProps() []interface{} { @@ -339,6 +345,12 @@ func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags { } func (test *testBinary) install(ctx ModuleContext, file android.Path) { + // TODO: (b/167308193) Switch to /data/local/tests/unrestricted as the default install base. + testInstallBase := "/data/local/tmp" + if ctx.inVendor() || ctx.useVndk() { + testInstallBase = "/data/local/tests/vendor" + } + dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data) for _, dataSrcPath := range dataSrcPaths { @@ -406,7 +418,9 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { } test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config, - test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config) + test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config, testInstallBase) + + test.extraTestConfigs = android.PathsForModuleSrc(ctx, test.Properties.Test_options.Extra_test_configs) test.binaryDecorator.baseInstaller.dir = "nativetest" test.binaryDecorator.baseInstaller.dir64 = "nativetest64" diff --git a/cc/testing.go b/cc/testing.go index 06e5f832c..52f082990 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -527,7 +527,9 @@ func CreateTestContext() *android.TestContext { ctx.RegisterModuleType("filegroup", android.FileGroupFactory) ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory) ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory) + ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory) ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory) + ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory) ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) android.RegisterPrebuiltMutators(ctx) RegisterRequiredBuildComponentsForTest(ctx) diff --git a/cc/tidy.go b/cc/tidy.go index 364e56c5d..17471e674 100644 --- a/cc/tidy.go +++ b/cc/tidy.go @@ -109,7 +109,8 @@ func (tidy *tidyFeature) flags(ctx ModuleContext, flags Flags) Flags { tidyChecks += config.TidyChecksForDir(ctx.ModuleDir()) } if len(tidy.Properties.Tidy_checks) > 0 { - tidyChecks = tidyChecks + "," + strings.Join(esc(tidy.Properties.Tidy_checks), ",") + tidyChecks = tidyChecks + "," + strings.Join(esc( + config.ClangRewriteTidyChecks(tidy.Properties.Tidy_checks)), ",") } if ctx.Windows() { // https://b.corp.google.com/issues/120614316 diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go index 042e012d9..19f5ea4f7 100644 --- a/cc/toolchain_library.go +++ b/cc/toolchain_library.go @@ -36,8 +36,7 @@ type toolchainLibraryProperties struct { type toolchainLibraryDecorator struct { *libraryDecorator - - stripper + stripper Stripper Properties toolchainLibraryProperties } @@ -89,8 +88,8 @@ func (library *toolchainLibraryDecorator) link(ctx ModuleContext, if library.stripper.StripProperties.Strip.Keep_symbols_list != nil { fileName := ctx.ModuleName() + staticLibraryExtension outputFile := android.PathForModuleOut(ctx, fileName) - buildFlags := flagsToBuilderFlags(flags) - library.stripper.stripStaticLib(ctx, srcPath, outputFile, buildFlags) + stripFlags := flagsToStripFlags(flags) + library.stripper.StripStaticLib(ctx, srcPath, outputFile, stripFlags) return outputFile } diff --git a/cc/util.go b/cc/util.go index af26268e2..40374bff7 100644 --- a/cc/util.go +++ b/cc/util.go @@ -97,9 +97,14 @@ func flagsToBuilderFlags(in Flags) builderFlags { protoOptionsFile: in.protoOptionsFile, yacc: in.Yacc, + lex: in.Lex, } } +func flagsToStripFlags(in Flags) StripFlags { + return StripFlags{Toolchain: in.Toolchain} +} + func addPrefix(list []string, prefix string) []string { for i := range list { list[i] = prefix + list[i] diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go index e9d1c7378..85f514c83 100644 --- a/cc/vendor_public_library.go +++ b/cc/vendor_public_library.go @@ -144,7 +144,7 @@ func vendorPublicLibraryFactory() android.Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() stub := &vendorPublicLibraryStubDecorator{ libraryDecorator: library, diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go index e17a6d0b3..2819f4958 100644 --- a/cc/vendor_snapshot.go +++ b/cc/vendor_snapshot.go @@ -264,7 +264,7 @@ func vendorSnapshotLibrary(suffix string) (*Module, *vendorSnapshotLibraryDecora module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() prebuilt := &vendorSnapshotLibraryDecorator{ libraryDecorator: library, @@ -340,12 +340,12 @@ func (p *vendorSnapshotBinaryDecorator) link(ctx ModuleContext, } in := android.PathForModuleSrc(ctx, *p.properties.Src) - builderFlags := flagsToBuilderFlags(flags) + stripFlags := flagsToStripFlags(flags) p.unstrippedOutputFile = in binName := in.Base() - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { stripped := android.PathForModuleOut(ctx, "stripped", binName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -508,18 +508,51 @@ func isVendorProprietaryPath(dir string) bool { return false } +func isVendorProprietaryModule(ctx android.BaseModuleContext) bool { + + // Any module in a vendor proprietary path is a vendor proprietary + // module. + + if isVendorProprietaryPath(ctx.ModuleDir()) { + return true + } + + // However if the module is not in a vendor proprietary path, it may + // still be a vendor proprietary module. This happens for cc modules + // that are excluded from the vendor snapshot, and it means that the + // vendor has assumed control of the framework-provided module. + + if c, ok := ctx.Module().(*Module); ok { + if c.ExcludeFromVendorSnapshot() { + return true + } + } + + return false +} + // Determine if a module is going to be included in vendor snapshot or not. // // Targets of vendor snapshot are "vendor: true" or "vendor_available: true" modules in // AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might // depend on newer VNDK) So they are captured as vendor snapshot To build older vendor // image and newer system image altogether. -func isVendorSnapshotModule(m *Module, moduleDir string) bool { +func isVendorSnapshotModule(m *Module, inVendorProprietaryPath bool) bool { if !m.Enabled() || m.Properties.HideFromMake { return false } + // When android/prebuilt.go selects between source and prebuilt, it sets + // SkipInstall on the other one to avoid duplicate install rules in make. + if m.IsSkipInstall() { + return false + } // skip proprietary modules, but include all VNDK (static) - if isVendorProprietaryPath(moduleDir) && !m.IsVndk() { + if inVendorProprietaryPath && !m.IsVndk() { + return false + } + // If the module would be included based on its path, check to see if + // the module is marked to be excluded. If so, skip it. + if m.ExcludeFromVendorSnapshot() { return false } if m.Target().Os.Class != android.Device { @@ -791,7 +824,25 @@ func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonCont } moduleDir := ctx.ModuleDir(module) - if !isVendorSnapshotModule(m, moduleDir) { + inVendorProprietaryPath := isVendorProprietaryPath(moduleDir) + + if m.ExcludeFromVendorSnapshot() { + if inVendorProprietaryPath { + // Error: exclude_from_vendor_snapshot applies + // to framework-path modules only. + ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir) + return + } + if Bool(m.VendorProperties.Vendor_available) { + // Error: may not combine "vendor_available: + // true" with "exclude_from_vendor_snapshot: + // true". + ctx.Errorf("module %q may not use both \"vendor_available: true\" and \"exclude_from_vendor_snapshot: true\"", m.String()) + return + } + } + + if !isVendorSnapshotModule(m, inVendorProprietaryPath) { return } diff --git a/cc/vndk.go b/cc/vndk.go index 23bb095bc..9a2fa09d4 100644 --- a/cc/vndk.go +++ b/cc/vndk.go @@ -505,18 +505,25 @@ func (txt *vndkLibrariesTxt) AndroidMkEntries() []android.AndroidMkEntries { }} } +// PrebuiltEtcModule interface func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath { return txt.outputFile } -func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) { - return android.Paths{txt.outputFile}, nil +// PrebuiltEtcModule interface +func (txt *vndkLibrariesTxt) BaseDir() string { + return "etc" } +// PrebuiltEtcModule interface func (txt *vndkLibrariesTxt) SubDir() string { return "" } +func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) { + return android.Paths{txt.outputFile}, nil +} + func VndkSnapshotSingleton() android.Singleton { return &vndkSnapshotSingleton{} } diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index 5a44c4663..94847601e 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -142,9 +142,10 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, builderFlags := flagsToBuilderFlags(flags) p.unstrippedOutputFile = in libName := in.Base() - if p.needsStrip(ctx) { + if p.stripper.NeedsStrip(ctx) { + stripFlags := flagsToStripFlags(flags) stripped := android.PathForModuleOut(ctx, "stripped", libName) - p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags) + p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags) in = stripped } @@ -213,7 +214,7 @@ func vndkPrebuiltSharedLibrary() *Module { library.BuildOnlyShared() module.stl = nil module.sanitize = nil - library.StripProperties.Strip.None = BoolPtr(true) + library.disableStripping() prebuilt := &vndkPrebuiltLibraryDecorator{ libraryDecorator: library, diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp index 7b8352b6a..4ebbe6895 100644 --- a/cmd/soong_build/Android.bp +++ b/cmd/soong_build/Android.bp @@ -28,5 +28,8 @@ bootstrap_go_binary { "writedocs.go", "bazel_overlay.go", ], + testSrcs: [ + "bazel_overlay_test.go", + ], primaryBuilder: true, } diff --git a/cmd/soong_build/bazel_overlay.go b/cmd/soong_build/bazel_overlay.go index e37c163d4..72e0fbdf5 100644 --- a/cmd/soong_build/bazel_overlay.go +++ b/cmd/soong_build/bazel_overlay.go @@ -20,39 +20,51 @@ import ( "io/ioutil" "os" "path/filepath" + "reflect" "strings" "github.com/google/blueprint" + "github.com/google/blueprint/bootstrap/bpdoc" + "github.com/google/blueprint/proptools" ) const ( + // The default `load` preamble for every generated BUILD file. soongModuleLoad = `package(default_visibility = ["//visibility:public"]) load("//:soong_module.bzl", "soong_module") + ` - // A BUILD file target snippet representing a Soong module + // A macro call in the BUILD file representing a Soong module, with space + // for expanding more attributes. soongModuleTarget = `soong_module( name = "%s", module_name = "%s", module_type = "%s", module_variant = "%s", - deps = [ - %s - ], -) -` + module_deps = %s, +%s)` - // The soong_module rule implementation in a .bzl file - soongModuleBzl = ` -SoongModuleInfo = provider( + // A simple provider to mark and differentiate Soong module rule shims from + // regular Bazel rules. Every Soong module rule shim returns a + // SoongModuleInfo provider, and can only depend on rules returning + // SoongModuleInfo in the `module_deps` attribute. + providersBzl = `SoongModuleInfo = provider( fields = { "name": "Name of module", "type": "Type of module", "variant": "Variant of module", }, ) +` -def _soong_module_impl(ctx): + // The soong_module rule implementation in a .bzl file. + soongModuleBzl = ` +%s + +load(":providers.bzl", "SoongModuleInfo") + +def _generic_soong_module_impl(ctx): return [ SoongModuleInfo( name = ctx.attr.module_name, @@ -61,21 +73,124 @@ def _soong_module_impl(ctx): ), ] -soong_module = rule( - implementation = _soong_module_impl, +generic_soong_module = rule( + implementation = _generic_soong_module_impl, attrs = { "module_name": attr.string(mandatory = True), "module_type": attr.string(mandatory = True), "module_variant": attr.string(), - "deps": attr.label_list(providers = [SoongModuleInfo]), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), }, ) + +soong_module_rule_map = { +%s} + +_SUPPORTED_TYPES = ["bool", "int", "string"] + +def _is_supported_type(value): + if type(value) in _SUPPORTED_TYPES: + return True + elif type(value) == "list": + supported = True + for v in value: + supported = supported and type(v) in _SUPPORTED_TYPES + return supported + else: + return False + +# soong_module is a macro that supports arbitrary kwargs, and uses module_type to +# expand to the right underlying shim. +def soong_module(name, module_type, **kwargs): + soong_module_rule = soong_module_rule_map.get(module_type) + + if soong_module_rule == None: + # This module type does not have an existing rule to map to, so use the + # generic_soong_module rule instead. + generic_soong_module( + name = name, + module_type = module_type, + module_name = kwargs.pop("module_name", ""), + module_variant = kwargs.pop("module_variant", ""), + module_deps = kwargs.pop("module_deps", []), + ) + else: + supported_kwargs = dict() + for key, value in kwargs.items(): + if _is_supported_type(value): + supported_kwargs[key] = value + soong_module_rule( + name = name, + **supported_kwargs, + ) +` + + // A rule shim for representing a Soong module type and its properties. + moduleRuleShim = ` +def _%[1]s_impl(ctx): + return [SoongModuleInfo()] + +%[1]s = rule( + implementation = _%[1]s_impl, + attrs = %[2]s +) ` ) +var ( + // An allowlist of prop types that are surfaced from module props to rule + // attributes. (nested) dictionaries are notably absent here, because while + // Soong supports multi value typed and nested dictionaries, Bazel's rule + // attr() API supports only single-level string_dicts. + allowedPropTypes = map[string]bool{ + "int": true, // e.g. 42 + "bool": true, // e.g. True + "string_list": true, // e.g. ["a", "b"] + "string": true, // e.g. "a" + } + + // TODO(b/166563303): Specific properties of some module types aren't + // recognized by the documentation generator. As a workaround, hardcode a + // mapping of the module type to prop name to prop type here, and ultimately + // fix the documentation generator to also parse these properties correctly. + additionalPropTypes = map[string]map[string]string{ + // sdk and module_exports props are created at runtime using reflection. + // bpdocs isn't wired up to read runtime generated structs. + "sdk": { + "java_header_libs": "string_list", + "java_sdk_libs": "string_list", + "java_system_modules": "string_list", + "native_header_libs": "string_list", + "native_libs": "string_list", + "native_objects": "string_list", + "native_shared_libs": "string_list", + "native_static_libs": "string_list", + }, + "module_exports": { + "java_libs": "string_list", + "java_tests": "string_list", + "native_binaries": "string_list", + "native_shared_libs": "string_list", + }, + } + + // Certain module property names are blocklisted/ignored here, for the reasons commented. + ignoredPropNames = map[string]bool{ + "name": true, // redundant, since this is explicitly generated for every target + "from": true, // reserved keyword + "in": true, // reserved keyword + "arch": true, // interface prop type is not supported yet. + "multilib": true, // interface prop type is not supported yet. + "target": true, // interface prop type is not supported yet. + "visibility": true, // Bazel has native visibility semantics. Handle later. + "features": true, // There is already a built-in attribute 'features' which cannot be overridden. + } +) + func targetNameWithVariant(c *blueprint.Context, logicModule blueprint.Module) string { name := "" if c.ModuleSubDir(logicModule) != "" { + // TODO(b/162720883): Figure out a way to drop the "--" variant suffixes. name = c.ModuleName(logicModule) + "--" + c.ModuleSubDir(logicModule) } else { name = c.ModuleName(logicModule) @@ -95,6 +210,251 @@ func packagePath(c *blueprint.Context, logicModule blueprint.Module) string { return filepath.Dir(c.BlueprintFile(logicModule)) } +func escapeString(s string) string { + s = strings.ReplaceAll(s, "\\", "\\\\") + return strings.ReplaceAll(s, "\"", "\\\"") +} + +func makeIndent(indent int) string { + if indent < 0 { + panic(fmt.Errorf("indent column cannot be less than 0, but got %d", indent)) + } + return strings.Repeat(" ", indent) +} + +// prettyPrint a property value into the equivalent Starlark representation +// recursively. +func prettyPrint(propertyValue reflect.Value, indent int) (string, error) { + if isZero(propertyValue) { + // A property value being set or unset actually matters -- Soong does set default + // values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at + // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480 + // + // In Bazel-parlance, we would use "attr.<type>(default = <default value>)" to set the default + // value of unset attributes. + return "", nil + } + + var ret string + switch propertyValue.Kind() { + case reflect.String: + ret = fmt.Sprintf("\"%v\"", escapeString(propertyValue.String())) + case reflect.Bool: + ret = strings.Title(fmt.Sprintf("%v", propertyValue.Interface())) + case reflect.Int, reflect.Uint, reflect.Int64: + ret = fmt.Sprintf("%v", propertyValue.Interface()) + case reflect.Ptr: + return prettyPrint(propertyValue.Elem(), indent) + case reflect.Slice: + ret = "[\n" + for i := 0; i < propertyValue.Len(); i++ { + indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1) + if err != nil { + return "", err + } + + if indexedValue != "" { + ret += makeIndent(indent + 1) + ret += indexedValue + ret += ",\n" + } + } + ret += makeIndent(indent) + ret += "]" + case reflect.Struct: + ret = "{\n" + // Sort and print the struct props by the key. + structProps := extractStructProperties(propertyValue, indent) + for _, k := range android.SortedStringKeys(structProps) { + ret += makeIndent(indent + 1) + ret += fmt.Sprintf("%q: %s,\n", k, structProps[k]) + } + ret += makeIndent(indent) + ret += "}" + case reflect.Interface: + // TODO(b/164227191): implement pretty print for interfaces. + // Interfaces are used for for arch, multilib and target properties. + return "", nil + default: + return "", fmt.Errorf( + "unexpected kind for property struct field: %s", propertyValue.Kind()) + } + return ret, nil +} + +// Converts a reflected property struct value into a map of property names and property values, +// which each property value correctly pretty-printed and indented at the right nest level, +// since property structs can be nested. In Starlark, nested structs are represented as nested +// dicts: https://docs.bazel.build/skylark/lib/dict.html +func extractStructProperties(structValue reflect.Value, indent int) map[string]string { + if structValue.Kind() != reflect.Struct { + panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind())) + } + + ret := map[string]string{} + structType := structValue.Type() + for i := 0; i < structValue.NumField(); i++ { + field := structType.Field(i) + if field.PkgPath != "" { + // Skip unexported fields. Some properties are + // internal to Soong only, and these fields do not have PkgPath. + continue + } + if proptools.HasTag(field, "blueprint", "mutated") { + continue + } + + fieldValue := structValue.Field(i) + if isZero(fieldValue) { + // Ignore zero-valued fields + continue + } + + propertyName := proptools.PropertyNameForField(field.Name) + prettyPrintedValue, err := prettyPrint(fieldValue, indent+1) + if err != nil { + panic( + fmt.Errorf( + "Error while parsing property: %q. %s", + propertyName, + err)) + } + if prettyPrintedValue != "" { + ret[propertyName] = prettyPrintedValue + } + } + + return ret +} + +func isStructPtr(t reflect.Type) bool { + return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct +} + +// Generically extract module properties and types into a map, keyed by the module property name. +func extractModuleProperties(aModule android.Module) map[string]string { + ret := map[string]string{} + + // Iterate over this android.Module's property structs. + for _, properties := range aModule.GetProperties() { + propertiesValue := reflect.ValueOf(properties) + // Check that propertiesValue is a pointer to the Properties struct, like + // *cc.BaseLinkerProperties or *java.CompilerProperties. + // + // propertiesValue can also be type-asserted to the structs to + // manipulate internal props, if needed. + if isStructPtr(propertiesValue.Type()) { + structValue := propertiesValue.Elem() + for k, v := range extractStructProperties(structValue, 0) { + ret[k] = v + } + } else { + panic(fmt.Errorf( + "properties must be a pointer to a struct, got %T", + propertiesValue.Interface())) + } + + } + + return ret +} + +// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as +// testonly = True, forcing other rules that depend on _test rules to also be +// marked as testonly = True. This semantic constraint is not present in Soong. +// To work around, rename "*_test" rules to "*_test_". +func canonicalizeModuleType(moduleName string) string { + if strings.HasSuffix(moduleName, "_test") { + return moduleName + "_" + } + + return moduleName +} + +type RuleShim struct { + // The rule class shims contained in a bzl file. e.g. ["cc_object", "cc_library", ..] + rules []string + + // The generated string content of the bzl file. + content string +} + +// Create <module>.bzl containing Bazel rule shims for every module type available in Soong and +// user-specified Go plugins. +// +// This function reuses documentation generation APIs to ensure parity between modules-as-docs +// and modules-as-code, including the names and types of module properties. +func createRuleShims(packages []*bpdoc.Package) (map[string]RuleShim, error) { + var propToAttr func(prop bpdoc.Property, propName string) string + propToAttr = func(prop bpdoc.Property, propName string) string { + // dots are not allowed in Starlark attribute names. Substitute them with double underscores. + propName = strings.ReplaceAll(propName, ".", "__") + if !shouldGenerateAttribute(propName) { + return "" + } + + // Canonicalize and normalize module property types to Bazel attribute types + starlarkAttrType := prop.Type + if starlarkAttrType == "list of strings" { + starlarkAttrType = "string_list" + } else if starlarkAttrType == "int64" { + starlarkAttrType = "int" + } else if starlarkAttrType == "" { + var attr string + for _, nestedProp := range prop.Properties { + nestedAttr := propToAttr(nestedProp, propName+"__"+nestedProp.Name) + if nestedAttr != "" { + // TODO(b/167662930): Fix nested props resulting in too many attributes. + // Let's still generate these, but comment them out. + attr += "# " + nestedAttr + } + } + return attr + } + + if !allowedPropTypes[starlarkAttrType] { + return "" + } + + return fmt.Sprintf(" %q: attr.%s(),\n", propName, starlarkAttrType) + } + + ruleShims := map[string]RuleShim{} + for _, pkg := range packages { + content := "load(\":providers.bzl\", \"SoongModuleInfo\")\n" + + bzlFileName := strings.ReplaceAll(pkg.Path, "android/soong/", "") + bzlFileName = strings.ReplaceAll(bzlFileName, ".", "_") + bzlFileName = strings.ReplaceAll(bzlFileName, "/", "_") + + rules := []string{} + + for _, moduleTypeTemplate := range moduleTypeDocsToTemplates(pkg.ModuleTypes) { + attrs := `{ + "module_name": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), +` + for _, prop := range moduleTypeTemplate.Properties { + attrs += propToAttr(prop, prop.Name) + } + + for propName, propType := range additionalPropTypes[moduleTypeTemplate.Name] { + attrs += fmt.Sprintf(" %q: attr.%s(),\n", propName, propType) + } + + attrs += " }," + + rule := canonicalizeModuleType(moduleTypeTemplate.Name) + content += fmt.Sprintf(moduleRuleShim, rule, attrs) + rules = append(rules, rule) + } + + ruleShims[bzlFileName] = RuleShim{content: content, rules: rules} + } + return ruleShims, nil +} + func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error { blueprintCtx := ctx.Context blueprintCtx.VisitAllModules(func(module blueprint.Module) { @@ -103,27 +463,7 @@ func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error { panic(err) } - // TODO(b/163018919): DirectDeps can have duplicate (module, variant) - // items, if the modules are added using different DependencyTag. Figure - // out the implications of that. - depLabels := map[string]bool{} - blueprintCtx.VisitDirectDeps(module, func(depModule blueprint.Module) { - depLabels[qualifiedTargetLabel(blueprintCtx, depModule)] = true - }) - - var depLabelList string - for depLabel, _ := range depLabels { - depLabelList += "\"" + depLabel + "\",\n " - } - buildFile.Write([]byte( - fmt.Sprintf( - soongModuleTarget, - targetNameWithVariant(blueprintCtx, module), - blueprintCtx.ModuleName(module), - blueprintCtx.ModuleType(module), - // misleading name, this actually returns the variant. - blueprintCtx.ModuleSubDir(module), - depLabelList))) + buildFile.Write([]byte(generateSoongModuleTarget(blueprintCtx, module) + "\n\n")) buildFile.Close() }) @@ -135,7 +475,98 @@ func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error { return err } - return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", soongModuleBzl) + if err := writeReadOnlyFile(bazelOverlayDir, "providers.bzl", providersBzl); err != nil { + return err + } + + packages, err := getPackages(ctx) + if err != nil { + return err + } + ruleShims, err := createRuleShims(packages) + if err != nil { + return err + } + + for bzlFileName, ruleShim := range ruleShims { + if err := writeReadOnlyFile(bazelOverlayDir, bzlFileName+".bzl", ruleShim.content); err != nil { + return err + } + } + + return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)) +} + +// Generate the content of soong_module.bzl with the rule shim load statements +// and mapping of module_type to rule shim map for every module type in Soong. +func generateSoongModuleBzl(bzlLoads map[string]RuleShim) string { + var loadStmts string + var moduleRuleMap string + for bzlFileName, ruleShim := range bzlLoads { + loadStmt := "load(\"//:" + loadStmt += bzlFileName + loadStmt += ".bzl\"" + for _, rule := range ruleShim.rules { + loadStmt += fmt.Sprintf(", %q", rule) + moduleRuleMap += " \"" + rule + "\": " + rule + ",\n" + } + loadStmt += ")\n" + loadStmts += loadStmt + } + + return fmt.Sprintf(soongModuleBzl, loadStmts, moduleRuleMap) +} + +func shouldGenerateAttribute(prop string) bool { + return !ignoredPropNames[prop] +} + +// props is an unsorted map. This function ensures that +// the generated attributes are sorted to ensure determinism. +func propsToAttributes(props map[string]string) string { + var attributes string + for _, propName := range android.SortedStringKeys(props) { + if shouldGenerateAttribute(propName) { + attributes += fmt.Sprintf(" %s = %s,\n", propName, props[propName]) + } + } + return attributes +} + +// Convert a module and its deps and props into a Bazel macro/rule +// representation in the BUILD file. +func generateSoongModuleTarget( + blueprintCtx *blueprint.Context, + module blueprint.Module) string { + + var props map[string]string + if aModule, ok := module.(android.Module); ok { + props = extractModuleProperties(aModule) + } + attributes := propsToAttributes(props) + + // TODO(b/163018919): DirectDeps can have duplicate (module, variant) + // items, if the modules are added using different DependencyTag. Figure + // out the implications of that. + depLabels := map[string]bool{} + blueprintCtx.VisitDirectDeps(module, func(depModule blueprint.Module) { + depLabels[qualifiedTargetLabel(blueprintCtx, depModule)] = true + }) + + depLabelList := "[\n" + for depLabel, _ := range depLabels { + depLabelList += fmt.Sprintf(" %q,\n", depLabel) + } + depLabelList += " ]" + + return fmt.Sprintf( + soongModuleTarget, + targetNameWithVariant(blueprintCtx, module), + blueprintCtx.ModuleName(module), + canonicalizeModuleType(blueprintCtx.ModuleType(module)), + blueprintCtx.ModuleSubDir(module), + depLabelList, + attributes) } func buildFileForModule(ctx *blueprint.Context, module blueprint.Module) (*os.File, error) { @@ -165,9 +596,41 @@ func buildFileForModule(ctx *blueprint.Context, module blueprint.Module) (*os.Fi return f, nil } -// The overlay directory should be read-only, sufficient for bazel query. +// The overlay directory should be read-only, sufficient for bazel query. The files +// are not intended to be edited by end users. func writeReadOnlyFile(dir string, baseName string, content string) error { - workspaceFile := filepath.Join(bazelOverlayDir, baseName) + pathToFile := filepath.Join(bazelOverlayDir, baseName) // 0444 is read-only - return ioutil.WriteFile(workspaceFile, []byte(content), 0444) + return ioutil.WriteFile(pathToFile, []byte(content), 0444) +} + +func isZero(value reflect.Value) bool { + switch value.Kind() { + case reflect.Func, reflect.Map, reflect.Slice: + return value.IsNil() + case reflect.Array: + valueIsZero := true + for i := 0; i < value.Len(); i++ { + valueIsZero = valueIsZero && isZero(value.Index(i)) + } + return valueIsZero + case reflect.Struct: + valueIsZero := true + for i := 0; i < value.NumField(); i++ { + if value.Field(i).CanSet() { + valueIsZero = valueIsZero && isZero(value.Field(i)) + } + } + return valueIsZero + case reflect.Ptr: + if !value.IsNil() { + return isZero(reflect.Indirect(value)) + } else { + return true + } + default: + zeroValue := reflect.Zero(value.Type()) + result := value.Interface() == zeroValue.Interface() + return result + } } diff --git a/cmd/soong_build/bazel_overlay_test.go b/cmd/soong_build/bazel_overlay_test.go new file mode 100644 index 000000000..f0c851521 --- /dev/null +++ b/cmd/soong_build/bazel_overlay_test.go @@ -0,0 +1,464 @@ +// 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 main + +import ( + "android/soong/android" + "io/ioutil" + "os" + "strings" + "testing" + + "github.com/google/blueprint/bootstrap/bpdoc" +) + +var buildDir string + +func setUp() { + var err error + buildDir, err = ioutil.TempDir("", "bazel_overlay_test") + if err != nil { + panic(err) + } +} + +func tearDown() { + os.RemoveAll(buildDir) +} + +func TestMain(m *testing.M) { + run := func() int { + setUp() + defer tearDown() + + return m.Run() + } + + os.Exit(run()) +} + +type customModule struct { + android.ModuleBase +} + +func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // nothing for now. +} + +func customModuleFactory() android.Module { + module := &customModule{} + android.InitAndroidModule(module) + return module +} + +func TestGenerateBazelOverlayFromBlueprint(t *testing.T) { + testCases := []struct { + bp string + expectedBazelTarget string + }{ + { + bp: `custom { + name: "foo", +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], +)`, + }, + { + bp: `custom { + name: "foo", + ramdisk: true, +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + ramdisk = True, +)`, + }, + { + bp: `custom { + name: "foo", + owner: "a_string_with\"quotes\"_and_\\backslashes\\\\", +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + owner = "a_string_with\"quotes\"_and_\\backslashes\\\\", +)`, + }, + { + bp: `custom { + name: "foo", + required: ["bar"], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + required = [ + "bar", + ], +)`, + }, + { + bp: `custom { + name: "foo", + target_required: ["qux", "bazqux"], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + target_required = [ + "qux", + "bazqux", + ], +)`, + }, + { + bp: `custom { + name: "foo", + dist: { + targets: ["goal_foo"], + tag: ".foo", + }, + dists: [ + { + targets: ["goal_bar"], + tag: ".bar", + }, + ], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + dist = { + "tag": ".foo", + "targets": [ + "goal_foo", + ], + }, + dists = [ + { + "tag": ".bar", + "targets": [ + "goal_bar", + ], + }, + ], +)`, + }, + { + bp: `custom { + name: "foo", + required: ["bar"], + target_required: ["qux", "bazqux"], + ramdisk: true, + owner: "custom_owner", + dists: [ + { + tag: ".tag", + targets: ["my_goal"], + }, + ], +} + `, + expectedBazelTarget: `soong_module( + name = "foo", + module_name = "foo", + module_type = "custom", + module_variant = "", + module_deps = [ + ], + dists = [ + { + "tag": ".tag", + "targets": [ + "my_goal", + ], + }, + ], + owner = "custom_owner", + ramdisk = True, + required = [ + "bar", + ], + target_required = [ + "qux", + "bazqux", + ], +)`, + }, + } + + for _, testCase := range testCases { + config := android.TestConfig(buildDir, nil, testCase.bp, nil) + ctx := android.NewTestContext() + ctx.RegisterModuleType("custom", customModuleFactory) + ctx.Register(config) + + _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) + android.FailIfErrored(t, errs) + _, errs = ctx.PrepareBuildActions(config) + android.FailIfErrored(t, errs) + + module := ctx.ModuleForTests("foo", "").Module().(*customModule) + blueprintCtx := ctx.Context.Context + + actualBazelTarget := generateSoongModuleTarget(blueprintCtx, module) + if actualBazelTarget != testCase.expectedBazelTarget { + t.Errorf( + "Expected generated Bazel target to be '%s', got '%s'", + testCase.expectedBazelTarget, + actualBazelTarget, + ) + } + } +} + +func createPackageFixtures() []*bpdoc.Package { + properties := []bpdoc.Property{ + bpdoc.Property{ + Name: "int64_prop", + Type: "int64", + }, + bpdoc.Property{ + Name: "int_prop", + Type: "int", + }, + bpdoc.Property{ + Name: "bool_prop", + Type: "bool", + }, + bpdoc.Property{ + Name: "string_prop", + Type: "string", + }, + bpdoc.Property{ + Name: "string_list_prop", + Type: "list of strings", + }, + bpdoc.Property{ + Name: "nested_prop", + Type: "", + Properties: []bpdoc.Property{ + bpdoc.Property{ + Name: "int_prop", + Type: "int", + }, + bpdoc.Property{ + Name: "bool_prop", + Type: "bool", + }, + bpdoc.Property{ + Name: "string_prop", + Type: "string", + }, + }, + }, + bpdoc.Property{ + Name: "unknown_type", + Type: "unknown", + }, + } + + fooPropertyStruct := &bpdoc.PropertyStruct{ + Name: "FooProperties", + Properties: properties, + } + + moduleTypes := []*bpdoc.ModuleType{ + &bpdoc.ModuleType{ + Name: "foo_library", + PropertyStructs: []*bpdoc.PropertyStruct{ + fooPropertyStruct, + }, + }, + + &bpdoc.ModuleType{ + Name: "foo_binary", + PropertyStructs: []*bpdoc.PropertyStruct{ + fooPropertyStruct, + }, + }, + &bpdoc.ModuleType{ + Name: "foo_test", + PropertyStructs: []*bpdoc.PropertyStruct{ + fooPropertyStruct, + }, + }, + } + + return [](*bpdoc.Package){ + &bpdoc.Package{ + Name: "foo_language", + Path: "android/soong/foo", + ModuleTypes: moduleTypes, + }, + } +} + +func TestGenerateModuleRuleShims(t *testing.T) { + ruleShims, err := createRuleShims(createPackageFixtures()) + if err != nil { + panic(err) + } + + if len(ruleShims) != 1 { + t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims)) + } + + fooRuleShim := ruleShims["foo"] + expectedRules := []string{"foo_binary", "foo_library", "foo_test_"} + + if len(fooRuleShim.rules) != 3 { + t.Errorf("Expected 3 rules, but got %d", len(fooRuleShim.rules)) + } + + for i, rule := range fooRuleShim.rules { + if rule != expectedRules[i] { + t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule) + } + } + + expectedBzl := `load(":providers.bzl", "SoongModuleInfo") + +def _foo_binary_impl(ctx): + return [SoongModuleInfo()] + +foo_binary = rule( + implementation = _foo_binary_impl, + attrs = { + "module_name": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), + "bool_prop": attr.bool(), + "int64_prop": attr.int(), + "int_prop": attr.int(), +# "nested_prop__int_prop": attr.int(), +# "nested_prop__bool_prop": attr.bool(), +# "nested_prop__string_prop": attr.string(), + "string_list_prop": attr.string_list(), + "string_prop": attr.string(), + }, +) + +def _foo_library_impl(ctx): + return [SoongModuleInfo()] + +foo_library = rule( + implementation = _foo_library_impl, + attrs = { + "module_name": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), + "bool_prop": attr.bool(), + "int64_prop": attr.int(), + "int_prop": attr.int(), +# "nested_prop__int_prop": attr.int(), +# "nested_prop__bool_prop": attr.bool(), +# "nested_prop__string_prop": attr.string(), + "string_list_prop": attr.string_list(), + "string_prop": attr.string(), + }, +) + +def _foo_test__impl(ctx): + return [SoongModuleInfo()] + +foo_test_ = rule( + implementation = _foo_test__impl, + attrs = { + "module_name": attr.string(mandatory = True), + "module_variant": attr.string(), + "module_deps": attr.label_list(providers = [SoongModuleInfo]), + "bool_prop": attr.bool(), + "int64_prop": attr.int(), + "int_prop": attr.int(), +# "nested_prop__int_prop": attr.int(), +# "nested_prop__bool_prop": attr.bool(), +# "nested_prop__string_prop": attr.string(), + "string_list_prop": attr.string_list(), + "string_prop": attr.string(), + }, +) +` + + if fooRuleShim.content != expectedBzl { + t.Errorf( + "Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s", + expectedBzl, + fooRuleShim.content) + } +} + +func TestGenerateSoongModuleBzl(t *testing.T) { + ruleShims, err := createRuleShims(createPackageFixtures()) + if err != nil { + panic(err) + } + actualSoongModuleBzl := generateSoongModuleBzl(ruleShims) + + expectedLoad := "load(\"//:foo.bzl\", \"foo_binary\", \"foo_library\", \"foo_test_\")" + expectedRuleMap := `soong_module_rule_map = { + "foo_binary": foo_binary, + "foo_library": foo_library, + "foo_test_": foo_test_, +}` + if !strings.Contains(actualSoongModuleBzl, expectedLoad) { + t.Errorf( + "Generated soong_module.bzl:\n\n%s\n\n"+ + "Could not find the load statement in the generated soong_module.bzl:\n%s", + actualSoongModuleBzl, + expectedLoad) + } + + if !strings.Contains(actualSoongModuleBzl, expectedRuleMap) { + t.Errorf( + "Generated soong_module.bzl:\n\n%s\n\n"+ + "Could not find the module -> rule map in the generated soong_module.bzl:\n%s", + actualSoongModuleBzl, + expectedRuleMap) + } +} diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go index c1368469c..5fb6e6ba2 100644 --- a/cmd/soong_build/writedocs.go +++ b/cmd/soong_build/writedocs.go @@ -95,14 +95,17 @@ func moduleTypeDocsToTemplates(moduleTypeList []*bpdoc.ModuleType) []moduleTypeT return result } -func writeDocs(ctx *android.Context, filename string) error { +func getPackages(ctx *android.Context) ([]*bpdoc.Package, error) { moduleTypeFactories := android.ModuleTypeFactories() bpModuleTypeFactories := make(map[string]reflect.Value) for moduleType, factory := range moduleTypeFactories { bpModuleTypeFactories[moduleType] = reflect.ValueOf(factory) } + return bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories) +} - packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories) +func writeDocs(ctx *android.Context, filename string) error { + packages, err := getPackages(ctx) if err != nil { return err } diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index 69e4f696c..4aa62be3c 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -173,6 +173,7 @@ func main() { rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb") soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics") defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile) + defer build.PrintGomaDeprecation(buildCtx, config) os.MkdirAll(logsDir, 0777) log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log")) diff --git a/dexpreopt/config.go b/dexpreopt/config.go index db5e97ae9..21f7bb3ee 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -100,6 +100,23 @@ type GlobalSoongConfig struct { ConstructContext android.Path } +// These libs are added as optional dependencies (<uses-library> with android:required set to false). +// This is because they haven't existed prior to certain SDK version, but classes in them were in +// bootclasspath jars, etc. So making them hard dependencies (android:required=true) would prevent +// apps from being installed to such legacy devices. +var OptionalCompatUsesLibs = []string{ + "org.apache.http.legacy", + "android.test.base", + "android.test.mock", +} + +var CompatUsesLibs = []string{ + "android.hidl.base-V1.0-java", + "android.hidl.manager-V1.0-java", +} + +const UnknownInstallLibraryPath = "error" + // LibraryPath contains paths to the library DEX jar on host and on device. type LibraryPath struct { Host android.Path @@ -109,6 +126,68 @@ type LibraryPath struct { // LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar. type LibraryPaths map[string]*LibraryPath +// Add a new library path to the map, unless a path for this library already exists. +// If necessary, check that the build and install paths exist. +func (libPaths LibraryPaths) addLibraryPath(ctx android.ModuleContext, lib string, + hostPath, installPath android.Path, strict bool) { + + // If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is + // not found. However, this is likely to result is disabling dexpreopt, as it won't be + // possible to construct class loader context without on-host and on-device library paths. + strict = strict && !ctx.Config().AllowMissingDependencies() + + if hostPath == nil && strict { + android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib) + } + + if installPath == nil { + if android.InList(lib, CompatUsesLibs) || android.InList(lib, OptionalCompatUsesLibs) { + // Assume that compatibility libraries are installed in /system/framework. + installPath = android.PathForModuleInstall(ctx, "framework", lib+".jar") + } else if strict { + android.ReportPathErrorf(ctx, "unknown install path to <uses-library> '%s'", lib) + } + } + + // Add a library only if the build and install path to it is known. + if _, present := libPaths[lib]; !present { + var devicePath string + if installPath != nil { + devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath)) + } else { + // For some stub libraries the only known thing is the name of their implementation + // library, but the library itself is unavailable (missing or part of a prebuilt). In + // such cases we still need to add the library to <uses-library> tags in the manifest, + // but we cannot use if for dexpreopt. + devicePath = UnknownInstallLibraryPath + } + libPaths[lib] = &LibraryPath{hostPath, devicePath} + } +} + +// Add a new library path to the map. Enforce checks that the library paths exist. +func (libPaths LibraryPaths) AddLibraryPath(ctx android.ModuleContext, lib string, hostPath, installPath android.Path) { + libPaths.addLibraryPath(ctx, lib, hostPath, installPath, true) +} + +// Add a new library path to the map, if the library exists (name is not nil). +// Don't enforce checks that the library paths exist. Some libraries may be missing from the build, +// but their names still need to be added to <uses-library> tags in the manifest. +func (libPaths LibraryPaths) MaybeAddLibraryPath(ctx android.ModuleContext, lib *string, hostPath, installPath android.Path) { + if lib != nil { + libPaths.addLibraryPath(ctx, *lib, hostPath, installPath, false) + } +} + +// Add library paths from the second map to the first map (do not override existing entries). +func (libPaths LibraryPaths) AddLibraryPaths(otherPaths LibraryPaths) { + for lib, path := range otherPaths { + if _, present := libPaths[lib]; !present { + libPaths[lib] = path + } + } +} + type ModuleConfig struct { Name string DexLocation string // dex location on device @@ -360,7 +439,33 @@ func RegisterToolDeps(ctx android.BottomUpMutatorContext) { func dex2oatPathFromDep(ctx android.ModuleContext) android.Path { dex2oatBin := dex2oatModuleName(ctx.Config()) - dex2oatModule := ctx.GetDirectDepWithTag(dex2oatBin, dex2oatDepTag) + // Find the right dex2oat module, trying to follow PrebuiltDepTag from source + // to prebuilt if there is one. We wouldn't have to do this if the + // prebuilt_postdeps mutator that replaces source deps with prebuilt deps was + // run after RegisterToolDeps above, but changing that leads to ordering + // problems between mutators (RegisterToolDeps needs to run late to act on + // final variants, while prebuilt_postdeps needs to run before many of the + // PostDeps mutators, like the APEX mutators). Hence we need to dig out the + // prebuilt explicitly here instead. + var dex2oatModule android.Module + ctx.WalkDeps(func(child, parent android.Module) bool { + if parent == ctx.Module() && ctx.OtherModuleDependencyTag(child) == dex2oatDepTag { + // Found the source module, or prebuilt module that has replaced the source. + dex2oatModule = child + if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil { + return false // If it's the prebuilt we're done. + } else { + return true // Recurse to check if the source has a prebuilt dependency. + } + } + if parent == dex2oatModule && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag { + if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil && p.Prebuilt().UsePrebuilt() { + dex2oatModule = child // Found a prebuilt that should be used. + } + } + return false + }) + if dex2oatModule == nil { // If this happens there's probably a missing call to AddToolDeps in DepsMutator. panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin)) diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 8c9f0a2b5..4dbda49b3 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -37,7 +37,6 @@ import ( "fmt" "path/filepath" "runtime" - "sort" "strings" "android/soong/android" @@ -82,15 +81,14 @@ func GenerateDexpreoptRule(ctx android.PathContext, globalSoong *GlobalSoongConf } if !dexpreoptDisabled(ctx, global, module) { - // Don't preopt individual boot jars, they will be preopted together. - if !global.BootJars.ContainsJar(module.Name) { + if clc := genClassLoaderContext(ctx, global, module); clc != nil { appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) && !module.NoCreateAppImage generateDM := shouldGenerateDM(module, global) for archIdx, _ := range module.Archs { - dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM) + dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, *clc, profile, appImage, generateDM) } } } @@ -103,6 +101,11 @@ func dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *Mo return true } + // Don't preopt individual boot jars, they will be preopted together. + if global.BootJars.ContainsJar(module.Name) { + return true + } + // Don't preopt system server jars that are updatable. if global.UpdatableSystemServerJars.ContainsJar(module.Name) { return true @@ -208,15 +211,6 @@ type classLoaderContextMap map[int]*classLoaderContext const anySdkVersion int = 9999 // should go last in class loader context -func (m classLoaderContextMap) getSortedKeys() []int { - keys := make([]int, 0, len(m)) - for k := range m { - keys = append(keys, k) - } - sort.Ints(keys) - return keys -} - func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext { if _, ok := m[sdkVer]; !ok { m[sdkVer] = &classLoaderContext{} @@ -224,13 +218,17 @@ func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext { return m[sdkVer] } -func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) { +func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) bool { clc := m.getValue(sdkVer) for _, lib := range libs { - p := pathForLibrary(module, lib) - clc.Host = append(clc.Host, p.Host) - clc.Target = append(clc.Target, p.Device) + if p := pathForLibrary(module, lib); p != nil { + clc.Host = append(clc.Host, p.Host) + clc.Target = append(clc.Target, p.Device) + } else { + return false + } } + return true } func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathContext, module *ModuleConfig, libs ...string) { @@ -241,9 +239,79 @@ func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathC } } +// genClassLoaderContext generates host and target class loader context to be passed to the dex2oat +// command for the dexpreopted module. There are three possible cases: +// +// 1. System server jars. They have a special class loader context that includes other system +// server jars. +// +// 2. Library jars or APKs which have precise list of their <uses-library> libs. Their class loader +// context includes build and on-device paths to these libs. In some cases it may happen that +// the path to a <uses-library> is unknown (e.g. the dexpreopted module may depend on stubs +// library, whose implementation library is missing from the build altogether). In such case +// dexpreopting with the <uses-library> is impossible, and dexpreopting without it is pointless, +// as the runtime classpath won't match and the dexpreopted code will be discarded. Therefore in +// such cases the function returns nil, which disables dexpreopt. +// +// 2. All other library jars or APKs for which the exact <uses-library> list is unknown. They use +// the unsafe &-classpath workaround that means empty class loader context and absence of runtime +// check that the class loader context provided by the PackageManager agrees with the stored +// class loader context recorded in the .odex file. +// +func genClassLoaderContext(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) *classLoaderContextMap { + classLoaderContexts := make(classLoaderContextMap) + systemServerJars := NonUpdatableSystemServerJars(ctx, global) + + if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 { + // System server jars should be dexpreopted together: class loader context of each jar + // should include all preceding jars on the system server classpath. + classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...) + + } else if module.EnforceUsesLibraries { + // Unconditional class loader context. + usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...) + if !classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...) { + return nil + } + + // Conditional class loader context for API version < 28. + const httpLegacy = "org.apache.http.legacy" + if !contains(usesLibs, httpLegacy) { + if !classLoaderContexts.addLibs(28, module, httpLegacy) { + return nil + } + } + + // Conditional class loader context for API version < 29. + usesLibs29 := []string{ + "android.hidl.base-V1.0-java", + "android.hidl.manager-V1.0-java", + } + if !classLoaderContexts.addLibs(29, module, usesLibs29...) { + return nil + } + + // Conditional class loader context for API version < 30. + const testBase = "android.test.base" + if !contains(usesLibs, testBase) { + if !classLoaderContexts.addLibs(30, module, testBase) { + return nil + } + } + + } else { + // Pass special class loader context to skip the classpath and collision check. + // This will get removed once LOCAL_USES_LIBRARIES is enforced. + // Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default + // to the &. + } + + return &classLoaderContexts +} + func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig, - module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath, - appImage bool, generateDM bool) { + module *ModuleConfig, rule *android.RuleBuilder, archIdx int, classLoaderContexts classLoaderContextMap, + profile android.WritablePath, appImage bool, generateDM bool) { arch := module.Archs[archIdx] @@ -274,17 +342,12 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g invocationPath := odexPath.ReplaceExtension(ctx, "invocation") - classLoaderContexts := make(classLoaderContextMap) systemServerJars := NonUpdatableSystemServerJars(ctx, global) rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String())) rule.Command().FlagWithOutput("rm -f ", odexPath) if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 { - // System server jars should be dexpreopted together: class loader context of each jar - // should include all preceding jars on the system server classpath. - classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...) - // Copy the system server jar to a predefined location where dex2oat will find it. dexPathHost := SystemServerDexJarHostPath(ctx, module.Name) rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String())) @@ -298,29 +361,6 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g Implicits(clc.Host). Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clc.Target, ":") + "]") } else if module.EnforceUsesLibraries { - // Unconditional class loader context. - usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...) - classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...) - - // Conditional class loader context for API version < 28. - const httpLegacy = "org.apache.http.legacy" - if !contains(usesLibs, httpLegacy) { - classLoaderContexts.addLibs(28, module, httpLegacy) - } - - // Conditional class loader context for API version < 29. - usesLibs29 := []string{ - "android.hidl.base-V1.0-java", - "android.hidl.manager-V1.0-java", - } - classLoaderContexts.addLibs(29, module, usesLibs29...) - - // Conditional class loader context for API version < 30. - const testBase = "android.test.base" - if !contains(usesLibs, testBase) { - classLoaderContexts.addLibs(30, module, testBase) - } - // Generate command that saves target SDK version in a shell variable. if module.ManifestPath != nil { rule.Command().Text(`target_sdk_version="$(`). @@ -342,7 +382,7 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g cmd := rule.Command(). Text(`eval "$(`).Tool(globalSoong.ConstructContext). Text(` --target-sdk-version ${target_sdk_version}`) - for _, ver := range classLoaderContexts.getSortedKeys() { + for _, ver := range android.SortedIntKeys(classLoaderContexts) { clc := classLoaderContexts.getValue(ver) verString := fmt.Sprintf("%d", ver) if ver == anySdkVersion { @@ -550,11 +590,11 @@ func PathToLocation(path android.Path, arch android.ArchType) string { } func pathForLibrary(module *ModuleConfig, lib string) *LibraryPath { - path, ok := module.LibraryPaths[lib] - if !ok { - panic(fmt.Errorf("unknown library path for %q", lib)) + if path, ok := module.LibraryPaths[lib]; ok && path.Host != nil && path.Device != "error" { + return path + } else { + return nil } - return path } func makefileMatch(pattern, s string) bool { diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 0f7b8dffc..5dd2a8696 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -28,14 +28,17 @@ var pctx = android.NewPackageContext("android/soong/etc") func init() { pctx.Import("android/soong/android") + RegisterPrebuiltEtcBuildComponents(android.InitRegistrationContext) +} - android.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory) - android.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory) - android.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory) - android.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory) - android.RegisterModuleType("prebuilt_font", PrebuiltFontFactory) - android.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory) - android.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory) +func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory) + ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory) + ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory) + ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory) + ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory) + ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory) + ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory) } type prebuiltEtcProperties struct { @@ -70,6 +73,7 @@ type prebuiltEtcProperties struct { type PrebuiltEtcModule interface { android.Module + BaseDir() string SubDir() string OutputFile() android.OutputPath } @@ -167,6 +171,16 @@ func (p *PrebuiltEtc) SubDir() string { return proptools.String(p.properties.Relative_install_path) } +func (p *PrebuiltEtc) BaseDir() string { + // If soc install dir was specified and SOC specific is set, set the installDirPath to the specified + // socInstallDirBase. + installBaseDir := p.installDirBase + if p.SocSpecific() && p.socInstallDirBase != "" { + installBaseDir = p.socInstallDirBase + } + return installBaseDir +} + func (p *PrebuiltEtc) Installable() bool { return p.properties.Installable == nil || android.Bool(p.properties.Installable) } @@ -191,13 +205,7 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir") } - // If soc install dir was specified and SOC specific is set, set the installDirPath to the specified - // socInstallDirBase. - installBaseDir := p.installDirBase - if ctx.SocSpecific() && p.socInstallDirBase != "" { - installBaseDir = p.socInstallDirBase - } - p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir()) + p.installDirPath = android.PathForModuleInstall(ctx, p.BaseDir(), p.SubDir()) // This ensures that outputFilePath has the correct name for others to // use, as the source file may have a different name. @@ -8,4 +8,4 @@ replace github.com/golang/protobuf v0.0.0 => ../../external/golang-protobuf replace github.com/google/blueprint v0.0.0 => ../blueprint -go 1.13 +go 1.15 diff --git a/java/Android.bp b/java/Android.bp index e345014ce..92e8ca458 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -59,6 +59,7 @@ bootstrap_go_package { "device_host_converter_test.go", "dexpreopt_test.go", "dexpreopt_bootjars_test.go", + "hiddenapi_singleton_test.go", "java_test.go", "jdeps_test.go", "kotlin_test.go", diff --git a/java/aar.go b/java/aar.go index 778e1cd7a..667dd9de4 100644 --- a/java/aar.go +++ b/java/aar.go @@ -20,6 +20,7 @@ import ( "strings" "android/soong/android" + "android/soong/dexpreopt" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -99,7 +100,7 @@ type aapt struct { useEmbeddedNativeLibs bool useEmbeddedDex bool usesNonSdkApis bool - sdkLibraries []string + sdkLibraries dexpreopt.LibraryPaths hasNoCode bool LoggingParent string resourceFiles android.Paths @@ -231,6 +232,8 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries := aaptLibs(ctx, sdkContext) + a.sdkLibraries = sdkLibraries + // App manifest file manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile) @@ -357,7 +360,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, ex // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths, - staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries []string) { + staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries dexpreopt.LibraryPaths) { var sharedLibs android.Paths @@ -366,6 +369,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati sharedLibs = append(sharedLibs, sdkDep.jars...) } + sdkLibraries = make(dexpreopt.LibraryPaths) + ctx.VisitDirectDeps(func(module android.Module) { var exportPackage android.Path aarDep, _ := module.(AndroidLibraryDependency) @@ -373,6 +378,10 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati exportPackage = aarDep.ExportPackage() } + if dep, ok := module.(Dependency); ok { + sdkLibraries.AddLibraryPaths(dep.ExportedSdkLibs()) + } + switch ctx.OtherModuleDependencyTag(module) { case instrumentationForTag: // Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2. @@ -385,7 +394,8 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati // (including the java_sdk_library) itself then append any implicit sdk library // names to the list of sdk libraries to be added to the manifest. if component, ok := module.(SdkLibraryComponentDependency); ok { - sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...) + sdkLibraries.MaybeAddLibraryPath(ctx, component.OptionalImplicitSdkLibrary(), + component.DexJarBuildPath(), component.DexJarInstallPath()) } case frameworkResTag: @@ -397,7 +407,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...) transitiveStaticLibs = append(transitiveStaticLibs, exportPackage) transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...) - sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...) + sdkLibraries.AddLibraryPaths(aarDep.ExportedSdkLibs()) if aarDep.ExportedAssets().Valid() { assets = append(assets, aarDep.ExportedAssets().Path()) } @@ -428,7 +438,6 @@ func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStati transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs) transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests) - sdkLibraries = android.FirstUniqueStrings(sdkLibraries) return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries } @@ -465,8 +474,8 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.isLibrary = true - a.aapt.sdkLibraries = a.exportedSdkLibs a.aapt.buildActions(ctx, sdkContext(a)) + a.exportedSdkLibs = a.aapt.sdkLibraries ctx.CheckbuildFile(a.proguardOptionsFile) ctx.CheckbuildFile(a.exportPackage) @@ -749,7 +758,7 @@ func (a *AARImport) AidlIncludeDirs() android.Paths { return nil } -func (a *AARImport) ExportedSdkLibs() []string { +func (a *AARImport) ExportedSdkLibs() dexpreopt.LibraryPaths { return nil } diff --git a/java/android_manifest.go b/java/android_manifest.go index 84dee16c5..62cd11203 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -21,6 +21,7 @@ import ( "github.com/google/blueprint" "android/soong/android" + "android/soong/dexpreopt" ) var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer", @@ -41,18 +42,8 @@ var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger", }, "args", "libs") -// These two libs are added as optional dependencies (<uses-library> with -// android:required set to false). This is because they haven't existed in pre-P -// devices, but classes in them were in bootclasspath jars, etc. So making them -// hard dependencies (android:required=true) would prevent apps from being -// installed to such legacy devices. -var optionalUsesLibs = []string{ - "android.test.base", - "android.test.mock", -} - // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml -func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string, +func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries dexpreopt.LibraryPaths, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path { var args []string @@ -79,8 +70,8 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext args = append(args, "--use-embedded-dex") } - for _, usesLib := range sdkLibraries { - if inList(usesLib, optionalUsesLibs) { + for _, usesLib := range android.SortedStringKeys(sdkLibraries) { + if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) { args = append(args, "--optional-uses-library", usesLib) } else { args = append(args, "--uses-library", usesLib) diff --git a/java/androidmk.go b/java/androidmk.go index bc327cf68..65c44a329 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -121,15 +121,14 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile) } - entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...) + entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", android.SortedStringKeys(library.exportedSdkLibs)...) if len(library.additionalCheckedModules) != 0 { entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...) } - if library.dexer.proguardDictionary.Valid() { - entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary.Path()) - } + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary) + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.dexer.proguardUsageZip) entries.SetString("LOCAL_MODULE_STEM", library.Stem()) entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports) @@ -162,15 +161,23 @@ func (j *Test) AndroidMkEntries() []android.AndroidMkEntries { if j.testConfig != nil { entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig) } + androidMkWriteExtraTestConfigs(j.extraTestConfigs, entries) androidMkWriteTestData(j.data, entries) if !BoolDefault(j.testProperties.Auto_gen_config, true) { entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true") } + entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", j.testProperties.Test_mainline_modules...) }) return entriesList } +func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) { + if len(extraTestConfigs) > 0 { + entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...) + } +} + func (j *TestHelperLibrary) AndroidMkEntries() []android.AndroidMkEntries { entriesList := j.Library.AndroidMkEntries() entries := &entriesList[0] @@ -196,7 +203,7 @@ func (prebuilt *Import) AndroidMkEntries() []android.AndroidMkEntries { entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable)) entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion()) entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem()) }, }, @@ -332,9 +339,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { if app.jacocoReportClassesFile != nil { entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile) } - if app.dexer.proguardDictionary.Valid() { - entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary.Path()) - } + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary) + entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.dexer.proguardUsageZip) if app.Name() == "framework-res" { entries.SetString("LOCAL_MODULE_PATH", "$(TARGET_OUT_JAVA_LIBRARIES)") @@ -433,7 +439,9 @@ func (a *AndroidTest) AndroidMkEntries() []android.AndroidMkEntries { if a.testConfig != nil { entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig) } + androidMkWriteExtraTestConfigs(a.extraTestConfigs, entries) androidMkWriteTestData(a.data, entries) + entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", a.testProperties.Test_mainline_modules...) }) return entriesList @@ -501,53 +509,14 @@ func (jd *Javadoc) AndroidMkEntries() []android.AndroidMkEntries { func (ddoc *Droiddoc) AndroidMkEntries() []android.AndroidMkEntries { return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "JAVA_LIBRARIES", - OutputFile: android.OptionalPathForPath(ddoc.stubsSrcJar), + OutputFile: android.OptionalPathForPath(ddoc.Javadoc.docZip), Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(entries *android.AndroidMkEntries) { - if BoolDefault(ddoc.Javadoc.properties.Installable, true) && ddoc.Javadoc.docZip != nil { + if ddoc.Javadoc.docZip != nil { entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", ddoc.Javadoc.docZip) } - if ddoc.Javadoc.stubsSrcJar != nil { - entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", ddoc.Javadoc.stubsSrcJar) - } - }, - }, - ExtraFooters: []android.AndroidMkExtraFootersFunc{ - func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) { - if ddoc.checkCurrentApiTimestamp != nil { - fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-current-api") - fmt.Fprintln(w, ddoc.Name()+"-check-current-api:", - ddoc.checkCurrentApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: checkapi") - fmt.Fprintln(w, "checkapi:", - ddoc.checkCurrentApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: droidcore") - fmt.Fprintln(w, "droidcore: checkapi") - } - if ddoc.updateCurrentApiTimestamp != nil { - fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-update-current-api") - fmt.Fprintln(w, ddoc.Name()+"-update-current-api:", - ddoc.updateCurrentApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: update-api") - fmt.Fprintln(w, "update-api:", - ddoc.updateCurrentApiTimestamp.String()) - } - if ddoc.checkLastReleasedApiTimestamp != nil { - fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-last-released-api") - fmt.Fprintln(w, ddoc.Name()+"-check-last-released-api:", - ddoc.checkLastReleasedApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: checkapi") - fmt.Fprintln(w, "checkapi:", - ddoc.checkLastReleasedApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: droidcore") - fmt.Fprintln(w, "droidcore: checkapi") - } + entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !BoolDefault(ddoc.Javadoc.properties.Installable, true)) }, }, }} diff --git a/java/app.go b/java/app.go index e82004845..ae7373fc7 100755 --- a/java/app.go +++ b/java/app.go @@ -118,17 +118,17 @@ var TargetCpuAbi = map[string]string{ } func SupportedAbis(ctx android.ModuleContext) []string { - abiName := func(archVar string, deviceArch string) string { + abiName := func(targetIdx int, deviceArch string) string { if abi, found := TargetCpuAbi[deviceArch]; found { return abi } - ctx.ModuleErrorf("Invalid %s: %s", archVar, deviceArch) + ctx.ModuleErrorf("Target %d has invalid Arch: %s", targetIdx, deviceArch) return "BAD_ABI" } - result := []string{abiName("TARGET_ARCH", ctx.DeviceConfig().DeviceArch())} - if s := ctx.DeviceConfig().DeviceSecondaryArch(); s != "" { - result = append(result, abiName("TARGET_2ND_ARCH", s)) + var result []string + for i, target := range ctx.Config().Targets[android.Android] { + result = append(result, abiName(i, target.Arch.ArchType.String())) } return result } @@ -268,6 +268,9 @@ type overridableAppProperties struct { // the logging parent of this app. Logging_parent *string + + // Whether to rename the package in resources to the override name rather than the base name. Defaults to true. + Rename_resources_package *bool } // runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay @@ -284,8 +287,6 @@ type AndroidApp struct { aapt android.OverridableModuleBase - usesLibrary usesLibrary - certificate Certificate appProperties appProperties @@ -507,10 +508,23 @@ func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool { !a.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs } +func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string { + aaptFlags := []string{"--rename-manifest-package " + packageName} + if renameResourcesPackage { + // Required to rename the package name in the resources table. + aaptFlags = append(aaptFlags, "--rename-resources-package "+packageName) + } + return aaptFlags +} + func (a *AndroidApp) OverriddenManifestPackageName() string { return a.overriddenManifestPackageName } +func (a *AndroidApp) renameResourcesPackage() bool { + return proptools.BoolDefault(a.overridableAppProperties.Rename_resources_package, true) +} + func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis) @@ -543,7 +557,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { if !overridden { manifestPackageName = *a.overridableAppProperties.Package_name } - aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName) + aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, a.renameResourcesPackage())...) a.overriddenManifestPackageName = manifestPackageName } @@ -586,7 +600,7 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") } -func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { +func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext, sdkLibs dexpreopt.LibraryPaths) android.Path { a.dexpreopter.installPath = a.installPath(ctx) if a.dexProperties.Uncompress_dex == nil { // If the value was not force-set by the user, use reasonable default based on the module. @@ -597,7 +611,9 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx) a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx) + a.dexpreopter.libraryPaths.AddLibraryPaths(sdkLibs) a.dexpreopter.manifestFile = a.mergedManifestFile + a.exportedSdkLibs = make(dexpreopt.LibraryPaths) if ctx.ModuleName() != "framework-res" { a.Module.compile(ctx, a.aaptSrcJar) @@ -766,6 +782,15 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Process all building blocks, from AAPT to certificates. a.aaptBuildActions(ctx) + // The decision to enforce <uses-library> checks is made before adding implicit SDK libraries. + a.usesLibrary.freezeEnforceUsesLibraries() + + // Add implicit SDK libraries to <uses-library> list. + for _, usesLib := range android.SortedStringKeys(a.aapt.sdkLibraries) { + a.usesLibrary.addLib(usesLib, inList(usesLib, dexpreopt.OptionalCompatUsesLibs)) + } + + // Check that the <uses-library> list is coherent with the manifest. if a.usesLibrary.enforceUsesLibraries() { manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile) apkDeps = append(apkDeps, manifestCheckFile) @@ -778,7 +803,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.resources = a.aapt.resourceFiles a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() - dexJarFile := a.dexBuildActions(ctx) + dexJarFile := a.dexBuildActions(ctx, a.aapt.sdkLibraries) jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) jniJarFile := a.jniBuildActions(jniLibs, ctx) @@ -792,18 +817,32 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Build a final signed app package. packageFile := android.PathForModuleOut(ctx, a.installApkName+".apk") + v4SigningRequested := Bool(a.Module.deviceProperties.V4_signature) + var v4SignatureFile android.WritablePath = nil + if v4SigningRequested { + v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+".apk.idsig") + } var lineageFile android.Path if lineage := String(a.overridableAppProperties.Lineage); lineage != "" { lineageFile = android.PathForModuleSrc(ctx, lineage) } - CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, lineageFile) + CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile) a.outputFile = packageFile + if v4SigningRequested { + a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) + } for _, split := range a.aapt.splits { // Sign the split APKs packageFile := android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk") - CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, lineageFile) + if v4SigningRequested { + v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig") + } + CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile) a.extraOutputFiles = append(a.extraOutputFiles, packageFile) + if v4SigningRequested { + a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) + } } // Build an app bundle. @@ -963,6 +1002,8 @@ func (a *AndroidApp) OutputFiles(tag string) (android.Paths, error) { switch tag { case ".aapt.srcjar": return []android.Path{a.aaptSrcJar}, nil + case ".export-package.apk": + return []android.Path{a.exportPackage}, nil } return a.Library.OutputFiles(tag) } @@ -1005,8 +1046,7 @@ func AndroidAppFactory() android.Module { module.AddProperties( &module.aaptProperties, &module.appProperties, - &module.overridableAppProperties, - &module.usesLibrary.usesLibraryProperties) + &module.overridableAppProperties) android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) @@ -1031,8 +1071,9 @@ type AndroidTest struct { testProperties testProperties - testConfig android.Path - data android.Paths + testConfig android.Path + extraTestConfigs android.Paths + data android.Paths } func (a *AndroidTest) InstallInTestcases() bool { @@ -1060,6 +1101,7 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs) a.testConfig = a.FixTestConfig(ctx, testConfig) + a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs) a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) } @@ -1125,7 +1167,6 @@ func AndroidTestFactory() android.Module { &module.appProperties, &module.appTestProperties, &module.overridableAppProperties, - &module.usesLibrary.usesLibraryProperties, &module.testProperties) android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) @@ -1174,8 +1215,7 @@ func AndroidTestHelperAppFactory() android.Module { &module.aaptProperties, &module.appProperties, &module.appTestHelperAppProperties, - &module.overridableAppProperties, - &module.usesLibrary.usesLibraryProperties) + &module.overridableAppProperties) android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) @@ -1518,7 +1558,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext if lineage := String(a.properties.Lineage); lineage != "" { lineageFile = android.PathForModuleSrc(ctx, lineage) } - SignAppPackage(ctx, signed, dexOutput, certificates, lineageFile) + SignAppPackage(ctx, signed, dexOutput, certificates, nil, lineageFile) a.outputFile = signed } else { alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename) @@ -1689,7 +1729,6 @@ func AndroidTestImportFactory() android.Module { module := &AndroidTestImport{} module.AddProperties(&module.properties) module.AddProperties(&module.dexpreoptProperties) - module.AddProperties(&module.usesLibrary.usesLibraryProperties) module.AddProperties(&module.testProperties) module.AddProperties(&module.testImportProperties) module.populateAllVariantStructs() @@ -1792,7 +1831,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC if !overridden { manifestPackageName = *r.overridableProperties.Package_name } - aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName) + aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, false)...) } if r.overridableProperties.Target_package_name != nil { aaptLinkFlags = append(aaptLinkFlags, @@ -1808,7 +1847,7 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC if lineage := String(r.properties.Lineage); lineage != "" { lineageFile = android.PathForModuleSrc(ctx, lineage) } - SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, lineageFile) + SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile) r.certificate = certificates[0] r.outputFile = signed @@ -1873,6 +1912,11 @@ type UsesLibraryProperties struct { // If true, the list of uses_libs and optional_uses_libs modules must match the AndroidManifest.xml file. Defaults // to true if either uses_libs or optional_uses_libs is set. Will unconditionally default to true in the future. Enforce_uses_libs *bool + + // Optional name of the <uses-library> provided by this module. This is needed for non-SDK + // libraries, because SDK ones are automatically picked up by Soong. The <uses-library> name + // normally is the same as the module name, but there are exceptions. + Provides_uses_lib *string } // usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the @@ -1883,6 +1927,16 @@ type usesLibrary struct { usesLibraryProperties UsesLibraryProperties } +func (u *usesLibrary) addLib(lib string, optional bool) { + if !android.InList(lib, u.usesLibraryProperties.Uses_libs) && !android.InList(lib, u.usesLibraryProperties.Optional_uses_libs) { + if optional { + u.usesLibraryProperties.Optional_uses_libs = append(u.usesLibraryProperties.Optional_uses_libs, lib) + } else { + u.usesLibraryProperties.Uses_libs = append(u.usesLibraryProperties.Uses_libs, lib) + } + } +} + func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) { if !ctx.Config().UnbundledBuild() { ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...) @@ -1893,11 +1947,8 @@ func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs if hasFrameworkLibs { // Dexpreopt needs paths to the dex jars of these libraries in order to construct // class loader context for dex2oat. Add them as a dependency with a special tag. - ctx.AddVariationDependencies(nil, usesLibTag, - "org.apache.http.legacy", - "android.hidl.base-V1.0-java", - "android.hidl.manager-V1.0-java") - ctx.AddVariationDependencies(nil, usesLibTag, optionalUsesLibs...) + ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.CompatUsesLibs...) + ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.OptionalCompatUsesLibs...) } } } @@ -1918,27 +1969,11 @@ func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) dexpreopt.Libr ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) { dep := ctx.OtherModuleName(m) if lib, ok := m.(Dependency); ok { - buildPath := lib.DexJarBuildPath() - if buildPath == nil { - ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must"+ - " produce a dex jar, does it have installable: true?", dep) - return - } - - var devicePath string - installPath := lib.DexJarInstallPath() - if installPath == nil { - devicePath = filepath.Join("/system/framework", dep+".jar") - } else { - devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath)) - } - - usesLibPaths[dep] = &dexpreopt.LibraryPath{buildPath, devicePath} + usesLibPaths.AddLibraryPath(ctx, dep, lib.DexJarBuildPath(), lib.DexJarInstallPath()) } else if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{dep}) } else { - ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be "+ - "a java library", dep) + ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep) } }) } @@ -1955,6 +1990,12 @@ func (u *usesLibrary) enforceUsesLibraries() bool { return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, defaultEnforceUsesLibs) } +// Freeze the value of `enforce_uses_libs` based on the current values of `uses_libs` and `optional_uses_libs`. +func (u *usesLibrary) freezeEnforceUsesLibraries() { + enforce := u.enforceUsesLibraries() + u.usesLibraryProperties.Enforce_uses_libs = &enforce +} + // verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against the ones specified // in the uses_libs and optional_uses_libs properties. It returns the path to a copy of the manifest. func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path { diff --git a/java/app_builder.go b/java/app_builder.go index 014bd54f1..69e462c3d 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -52,7 +52,7 @@ var combineApk = pctx.AndroidStaticRule("combineApk", }) func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath, - packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, lineageFile android.Path) { + packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path) { unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk" unsignedApk := android.PathForModuleOut(ctx, unsignedApkName) @@ -73,10 +73,10 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa Implicits: deps, }) - SignAppPackage(ctx, outputFile, unsignedApk, certificates, lineageFile) + SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile) } -func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, lineageFile android.Path) { +func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, unsignedApk android.Path, certificates []Certificate, v4SignatureFile android.WritablePath, lineageFile android.Path) { var certificateArgs []string var deps android.Paths @@ -87,6 +87,11 @@ func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, u outputFiles := android.WritablePaths{signedApk} var flags []string + if v4SignatureFile != nil { + outputFiles = append(outputFiles, v4SignatureFile) + flags = append(flags, "--enable-v4") + } + if lineageFile != nil { flags = append(flags, "--lineage", lineageFile.String()) deps = append(deps, lineageFile) @@ -97,7 +102,7 @@ func SignAppPackage(ctx android.ModuleContext, signedApk android.WritablePath, u "certificates": strings.Join(certificateArgs, " "), "flags": strings.Join(flags, " "), } - if ctx.Config().IsEnvTrue("RBE_SIGNAPK") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") { rule = SignapkRE args["implicits"] = strings.Join(deps.Strings(), ",") args["outCommaList"] = strings.Join(outputFiles.Strings(), ",") @@ -236,7 +241,7 @@ func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.Writabl args := map[string]string{ "jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "), } - if ctx.Config().IsEnvTrue("RBE_ZIP") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ZIP") { rule = zipRE args["implicits"] = strings.Join(deps.Strings(), ",") } diff --git a/java/app_test.go b/java/app_test.go index a070318db..536797119 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -176,16 +176,17 @@ func TestAndroidAppSet_Variants(t *testing.T) { set: "prebuilts/apks/app.apks", }` testCases := []struct { - name string - deviceArch *string - deviceSecondaryArch *string - aaptPrebuiltDPI []string - sdkVersion int - expected map[string]string + name string + targets []android.Target + aaptPrebuiltDPI []string + sdkVersion int + expected map[string]string }{ { - name: "One", - deviceArch: proptools.StringPtr("x86"), + name: "One", + targets: []android.Target{ + {Os: android.Android, Arch: android.Arch{ArchType: android.X86}}, + }, aaptPrebuiltDPI: []string{"ldpi", "xxhdpi"}, sdkVersion: 29, expected: map[string]string{ @@ -197,11 +198,13 @@ func TestAndroidAppSet_Variants(t *testing.T) { }, }, { - name: "Two", - deviceArch: proptools.StringPtr("x86_64"), - deviceSecondaryArch: proptools.StringPtr("x86"), - aaptPrebuiltDPI: nil, - sdkVersion: 30, + name: "Two", + targets: []android.Target{ + {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64}}, + {Os: android.Android, Arch: android.Arch{ArchType: android.X86}}, + }, + aaptPrebuiltDPI: nil, + sdkVersion: 30, expected: map[string]string{ "abis": "X86_64,X86", "allow-prereleased": "false", @@ -216,8 +219,7 @@ func TestAndroidAppSet_Variants(t *testing.T) { config := testAppConfig(nil, bp, nil) config.TestProductVariables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI config.TestProductVariables.Platform_sdk_version = &test.sdkVersion - config.TestProductVariables.DeviceArch = test.deviceArch - config.TestProductVariables.DeviceSecondaryArch = test.deviceSecondaryArch + config.Targets[android.Android] = test.targets ctx := testContext() run(t, ctx, config) module := ctx.ModuleForTests("foo", "android_common") @@ -1038,6 +1040,35 @@ func TestAndroidResources(t *testing.T) { } } +func checkSdkVersion(t *testing.T, config android.Config, expectedSdkVersion string) { + ctx := testContext() + + run(t, ctx, config) + + foo := ctx.ModuleForTests("foo", "android_common") + link := foo.Output("package-res.apk") + linkFlags := strings.Split(link.Args["flags"], " ") + min := android.IndexList("--min-sdk-version", linkFlags) + target := android.IndexList("--target-sdk-version", linkFlags) + + if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 { + t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags) + } + + gotMinSdkVersion := linkFlags[min+1] + gotTargetSdkVersion := linkFlags[target+1] + + if gotMinSdkVersion != expectedSdkVersion { + t.Errorf("incorrect --min-sdk-version, expected %q got %q", + expectedSdkVersion, gotMinSdkVersion) + } + + if gotTargetSdkVersion != expectedSdkVersion { + t.Errorf("incorrect --target-sdk-version, expected %q got %q", + expectedSdkVersion, gotTargetSdkVersion) + } +} + func TestAppSdkVersion(t *testing.T) { testCases := []struct { name string @@ -1107,34 +1138,81 @@ func TestAppSdkVersion(t *testing.T) { config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal + checkSdkVersion(t, config, test.expectedMinSdkVersion) - ctx := testContext() - - run(t, ctx, config) - - foo := ctx.ModuleForTests("foo", "android_common") - link := foo.Output("package-res.apk") - linkFlags := strings.Split(link.Args["flags"], " ") - min := android.IndexList("--min-sdk-version", linkFlags) - target := android.IndexList("--target-sdk-version", linkFlags) - - if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 { - t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags) - } - - gotMinSdkVersion := linkFlags[min+1] - gotTargetSdkVersion := linkFlags[target+1] + }) + } + } +} - if gotMinSdkVersion != test.expectedMinSdkVersion { - t.Errorf("incorrect --min-sdk-version, expected %q got %q", - test.expectedMinSdkVersion, gotMinSdkVersion) - } +func TestVendorAppSdkVersion(t *testing.T) { + testCases := []struct { + name string + sdkVersion string + platformSdkInt int + platformSdkCodename string + platformSdkFinal bool + deviceCurrentApiLevelForVendorModules string + expectedMinSdkVersion string + }{ + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "REL", + platformSdkFinal: true, + deviceCurrentApiLevelForVendorModules: "29", + expectedMinSdkVersion: "29", + }, + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "REL", + platformSdkFinal: true, + deviceCurrentApiLevelForVendorModules: "28", + expectedMinSdkVersion: "28", + }, + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "Q", + platformSdkFinal: false, + deviceCurrentApiLevelForVendorModules: "current", + expectedMinSdkVersion: "Q", + }, + { + name: "current final SDK", + sdkVersion: "current", + platformSdkInt: 29, + platformSdkCodename: "Q", + platformSdkFinal: false, + deviceCurrentApiLevelForVendorModules: "28", + expectedMinSdkVersion: "28", + }, + } - if gotTargetSdkVersion != test.expectedMinSdkVersion { - t.Errorf("incorrect --target-sdk-version, expected %q got %q", - test.expectedMinSdkVersion, gotTargetSdkVersion) - } - }) + for _, moduleType := range []string{"android_app", "android_library"} { + for _, sdkKind := range []string{"", "system_"} { + for _, test := range testCases { + t.Run(moduleType+" "+test.name, func(t *testing.T) { + bp := fmt.Sprintf(`%s { + name: "foo", + srcs: ["a.java"], + sdk_version: "%s%s", + vendor: true, + }`, moduleType, sdkKind, test.sdkVersion) + + config := testAppConfig(nil, bp, nil) + config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt + config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename + config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal + config.TestProductVariables.DeviceCurrentApiLevelForVendorModules = &test.deviceCurrentApiLevelForVendorModules + config.TestProductVariables.DeviceSystemSdkVersions = []string{"28", "29"} + checkSdkVersion(t, config, test.expectedMinSdkVersion) + }) + } } } } @@ -1579,6 +1657,66 @@ func TestCertificates(t *testing.T) { } } +func TestRequestV4SigningFlag(t *testing.T) { + testCases := []struct { + name string + bp string + expected string + }{ + { + name: "default", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + } + `, + expected: "", + }, + { + name: "default", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + v4_signature: false, + } + `, + expected: "", + }, + { + name: "module certificate property", + bp: ` + android_app { + name: "foo", + srcs: ["a.java"], + sdk_version: "current", + v4_signature: true, + } + `, + expected: "--enable-v4", + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + config := testAppConfig(nil, test.bp, nil) + ctx := testContext() + + run(t, ctx, config) + foo := ctx.ModuleForTests("foo", "android_common") + + signapk := foo.Output("foo.apk") + signFlags := signapk.Args["flags"] + if test.expected != signFlags { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", test.expected, signFlags) + } + }) + } +} + func TestPackageNameOverride(t *testing.T) { testCases := []struct { name string @@ -1701,52 +1839,125 @@ func TestOverrideAndroidApp(t *testing.T) { base: "foo", package_name: "org.dandroid.bp", } + + override_android_app { + name: "baz_no_rename_resources", + base: "foo", + package_name: "org.dandroid.bp", + rename_resources_package: false, + } + + android_app { + name: "foo_no_rename_resources", + srcs: ["a.java"], + certificate: "expiredkey", + overrides: ["qux"], + rename_resources_package: false, + sdk_version: "current", + } + + override_android_app { + name: "baz_base_no_rename_resources", + base: "foo_no_rename_resources", + package_name: "org.dandroid.bp", + } + + override_android_app { + name: "baz_override_base_rename_resources", + base: "foo_no_rename_resources", + package_name: "org.dandroid.bp", + rename_resources_package: true, + } `) expectedVariants := []struct { - moduleName string - variantName string - apkName string - apkPath string - certFlag string - lineageFlag string - overrides []string - aaptFlag string - logging_parent string + name string + moduleName string + variantName string + apkName string + apkPath string + certFlag string + lineageFlag string + overrides []string + packageFlag string + renameResources bool + logging_parent string }{ { - moduleName: "foo", - variantName: "android_common", - apkPath: "/target/product/test_device/system/app/foo/foo.apk", - certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", - lineageFlag: "", - overrides: []string{"qux"}, - aaptFlag: "", - logging_parent: "", - }, - { - moduleName: "bar", - variantName: "android_common_bar", - apkPath: "/target/product/test_device/system/app/bar/bar.apk", - certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", - lineageFlag: "--lineage lineage.bin", - overrides: []string{"qux", "foo"}, - aaptFlag: "", - logging_parent: "bah", + name: "foo", + moduleName: "foo", + variantName: "android_common", + apkPath: "/target/product/test_device/system/app/foo/foo.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux"}, + packageFlag: "", + renameResources: false, + logging_parent: "", + }, + { + name: "foo", + moduleName: "bar", + variantName: "android_common_bar", + apkPath: "/target/product/test_device/system/app/bar/bar.apk", + certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", + lineageFlag: "--lineage lineage.bin", + overrides: []string{"qux", "foo"}, + packageFlag: "", + renameResources: false, + logging_parent: "bah", }, { - moduleName: "baz", - variantName: "android_common_baz", - apkPath: "/target/product/test_device/system/app/baz/baz.apk", - certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", - lineageFlag: "", - overrides: []string{"qux", "foo"}, - aaptFlag: "--rename-manifest-package org.dandroid.bp", - logging_parent: "", + name: "foo", + moduleName: "baz", + variantName: "android_common_baz", + apkPath: "/target/product/test_device/system/app/baz/baz.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo"}, + packageFlag: "org.dandroid.bp", + renameResources: true, + logging_parent: "", + }, + { + name: "foo", + moduleName: "baz_no_rename_resources", + variantName: "android_common_baz_no_rename_resources", + apkPath: "/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo"}, + packageFlag: "org.dandroid.bp", + renameResources: false, + logging_parent: "", + }, + { + name: "foo_no_rename_resources", + moduleName: "baz_base_no_rename_resources", + variantName: "android_common_baz_base_no_rename_resources", + apkPath: "/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo_no_rename_resources"}, + packageFlag: "org.dandroid.bp", + renameResources: false, + logging_parent: "", + }, + { + name: "foo_no_rename_resources", + moduleName: "baz_override_base_rename_resources", + variantName: "android_common_baz_override_base_rename_resources", + apkPath: "/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk", + certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", + lineageFlag: "", + overrides: []string{"qux", "foo_no_rename_resources"}, + packageFlag: "org.dandroid.bp", + renameResources: true, + logging_parent: "", }, } for _, expected := range expectedVariants { - variant := ctx.ModuleForTests("foo", expected.variantName) + variant := ctx.ModuleForTests(expected.name, expected.variantName) // Check the final apk name outputs := variant.AllOutputs() @@ -1792,9 +2003,12 @@ func TestOverrideAndroidApp(t *testing.T) { // Check the package renaming flag, if exists. res := variant.Output("package-res.apk") aapt2Flags := res.Args["flags"] - if !strings.Contains(aapt2Flags, expected.aaptFlag) { - t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags) + checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + expectedPackage := expected.packageFlag + if !expected.renameResources { + expectedPackage = "" } + checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expectedPackage) } } @@ -1931,6 +2145,7 @@ func TestOverrideAndroidTest(t *testing.T) { res := variant.Output("package-res.apk") aapt2Flags := res.Args["flags"] checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expected.packageFlag) checkAapt2LinkFlag(t, aapt2Flags, "rename-instrumentation-target-package", expected.targetPackageFlag) } } @@ -2526,10 +2741,37 @@ func TestUsesLibraries(t *testing.T) { sdk_version: "current", } + java_sdk_library { + name: "runtime-library", + srcs: ["a.java"], + sdk_version: "current", + } + + java_library { + name: "static-runtime-helper", + srcs: ["a.java"], + libs: ["runtime-library"], + sdk_version: "current", + } + android_app { name: "app", srcs: ["a.java"], + libs: ["qux", "quuz"], + static_libs: ["static-runtime-helper"], + uses_libs: ["foo"], + sdk_version: "current", + optional_uses_libs: [ + "bar", + "baz", + ], + } + + android_app { + name: "app_with_stub_deps", + srcs: ["a.java"], libs: ["qux", "quuz.stubs"], + static_libs: ["static-runtime-helper"], uses_libs: ["foo"], sdk_version: "current", optional_uses_libs: [ @@ -2558,15 +2800,15 @@ func TestUsesLibraries(t *testing.T) { run(t, ctx, config) app := ctx.ModuleForTests("app", "android_common") + appWithStubDeps := ctx.ModuleForTests("app_with_stub_deps", "android_common") prebuilt := ctx.ModuleForTests("prebuilt", "android_common") // Test that implicit dependencies on java_sdk_library instances are passed to the manifest. manifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"] - if w := "--uses-library qux"; !strings.Contains(manifestFixerArgs, w) { - t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) - } - if w := "--uses-library quuz"; !strings.Contains(manifestFixerArgs, w) { - t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) + for _, w := range []string{"qux", "quuz", "runtime-library"} { + if !strings.Contains(manifestFixerArgs, "--uses-library "+w) { + t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs) + } } // Test that all libraries are verified @@ -2589,15 +2831,24 @@ func TestUsesLibraries(t *testing.T) { t.Errorf("wanted %q in %q", w, cmd) } - // Test that only present libraries are preopted + // Test that all present libraries are preopted, including implicit SDK dependencies cmd = app.Rule("dexpreopt").RuleParams.Command - - if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) { + w := `--target-classpath-for-sdk any` + + ` /system/framework/foo.jar` + + `:/system/framework/quuz.jar` + + `:/system/framework/qux.jar` + + `:/system/framework/runtime-library.jar` + + `:/system/framework/bar.jar` + if !strings.Contains(cmd, w) { t.Errorf("wanted %q in %q", w, cmd) } - cmd = prebuilt.Rule("dexpreopt").RuleParams.Command + // TODO(skvadrik) fix dexpreopt for stub libraries for which the implementation is present + if appWithStubDeps.MaybeRule("dexpreopt").RuleParams.Command != "" { + t.Errorf("dexpreopt should be disabled for apps with dependencies on stub libraries") + } + cmd = prebuilt.Rule("dexpreopt").RuleParams.Command if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) { t.Errorf("wanted %q in %q", w, cmd) } @@ -3019,6 +3270,65 @@ func TestRuntimeResourceOverlay(t *testing.T) { } } +func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) { + ctx, config := testJava(t, ` + java_defaults { + name: "rro_defaults", + theme: "default_theme", + product_specific: true, + aaptflags: ["--keep-raw-values"], + } + + runtime_resource_overlay { + name: "foo_with_defaults", + defaults: ["rro_defaults"], + } + + runtime_resource_overlay { + name: "foo_barebones", + } + `) + + // + // RRO module with defaults + // + m := ctx.ModuleForTests("foo_with_defaults", "android_common") + + // Check AAPT2 link flags. + aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ") + expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"} + absentFlags := android.RemoveListFromList(expectedFlags, aapt2Flags) + if len(absentFlags) > 0 { + t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags) + } + + // Check device location. + path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] + expectedPath := []string{"/tmp/target/product/test_device/product/overlay/default_theme"} + if !reflect.DeepEqual(path, expectedPath) { + t.Errorf("Unexpected LOCAL_MODULE_PATH value: %q, expected: %q", path, expectedPath) + } + + // + // RRO module without defaults + // + m = ctx.ModuleForTests("foo_barebones", "android_common") + + // Check AAPT2 link flags. + aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ") + unexpectedFlags := "--keep-raw-values" + if inList(unexpectedFlags, aapt2Flags) { + t.Errorf("unexpected value, %q is present in aapt2 link flags, %q", unexpectedFlags, aapt2Flags) + } + + // Check device location. + path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] + expectedPath = []string{"/tmp/target/product/test_device/system/overlay"} + if !reflect.DeepEqual(path, expectedPath) { + t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath) + } +} + func TestOverrideRuntimeResourceOverlay(t *testing.T) { ctx, _ := testJava(t, ` runtime_resource_overlay { @@ -3090,65 +3400,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { res := variant.Output("package-res.apk") aapt2Flags := res.Args["flags"] checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag) + checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", "") checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag) } } - -func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) { - ctx, config := testJava(t, ` - java_defaults { - name: "rro_defaults", - theme: "default_theme", - product_specific: true, - aaptflags: ["--keep-raw-values"], - } - - runtime_resource_overlay { - name: "foo_with_defaults", - defaults: ["rro_defaults"], - } - - runtime_resource_overlay { - name: "foo_barebones", - } - `) - - // - // RRO module with defaults - // - m := ctx.ModuleForTests("foo_with_defaults", "android_common") - - // Check AAPT2 link flags. - aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ") - expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"} - absentFlags := android.RemoveListFromList(expectedFlags, aapt2Flags) - if len(absentFlags) > 0 { - t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags) - } - - // Check device location. - path := android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] - expectedPath := []string{"/tmp/target/product/test_device/product/overlay/default_theme"} - if !reflect.DeepEqual(path, expectedPath) { - t.Errorf("Unexpected LOCAL_MODULE_PATH value: %q, expected: %q", path, expectedPath) - } - - // - // RRO module without defaults - // - m = ctx.ModuleForTests("foo_barebones", "android_common") - - // Check AAPT2 link flags. - aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ") - unexpectedFlags := "--keep-raw-values" - if inList(unexpectedFlags, aapt2Flags) { - t.Errorf("unexpected value, %q is present in aapt2 link flags, %q", unexpectedFlags, aapt2Flags) - } - - // Check device location. - path = android.AndroidMkEntriesForTest(t, config, "", m.Module())[0].EntryMap["LOCAL_MODULE_PATH"] - expectedPath = []string{"/tmp/target/product/test_device/system/overlay"} - if !reflect.DeepEqual(path, expectedPath) { - t.Errorf("Unexpected LOCAL_MODULE_PATH value: %v, expected: %v", path, expectedPath) - } -} diff --git a/java/builder.go b/java/builder.go index 7318fcbad..3043e46db 100644 --- a/java/builder.go +++ b/java/builder.go @@ -385,7 +385,7 @@ func TransformJavaToHeaderClasses(ctx android.ModuleContext, outputFile android. "outDir": android.PathForModuleOut(ctx, "turbine", "classes").String(), "javaVersion": flags.javaVersion.String(), } - if ctx.Config().IsEnvTrue("RBE_TURBINE") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") { rule = turbineRE args["implicits"] = strings.Join(deps.Strings(), ",") } @@ -452,7 +452,7 @@ func transformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab annoDir = filepath.Join(shardDir, annoDir) } rule := javac - if ctx.Config().IsEnvTrue("RBE_JAVAC") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAVAC") { rule = javacRE } ctx.Build(pctx, android.BuildParams{ @@ -480,7 +480,7 @@ func TransformResourcesToJar(ctx android.ModuleContext, outputFile android.Writa jarArgs []string, deps android.Paths) { rule := jar - if ctx.Config().IsEnvTrue("RBE_JAR") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAR") { rule = jarRE } ctx.Build(pctx, android.BuildParams{ diff --git a/java/config/config.go b/java/config/config.go index ef1ecc8b0..31e2b0ffe 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -41,6 +41,7 @@ var ( InstrumentFrameworkModules = []string{ "framework", + "framework-minus-apex", "telephony-common", "services", "android.car", @@ -51,6 +52,7 @@ var ( "core-libart", // TODO: Could this be all updatable bootclasspath jars? "updatable-media", + "framework-mediaprovider", "framework-sdkextensions", "android.net.ipsec.ike", } @@ -148,9 +150,9 @@ func init() { pctx.HostBinToolVariable("DexpreoptGen", "dexpreopt_gen") pctx.VariableFunc("REJavaPool", remoteexec.EnvOverrideFunc("RBE_JAVA_POOL", "java16")) - pctx.VariableFunc("REJavacExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAVAC_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) - pctx.VariableFunc("RED8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_D8_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) - pctx.VariableFunc("RER8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_R8_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) + pctx.VariableFunc("REJavacExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAVAC_EXEC_STRATEGY", remoteexec.RemoteLocalFallbackExecStrategy)) + pctx.VariableFunc("RED8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_D8_EXEC_STRATEGY", remoteexec.RemoteLocalFallbackExecStrategy)) + pctx.VariableFunc("RER8ExecStrategy", remoteexec.EnvOverrideFunc("RBE_R8_EXEC_STRATEGY", remoteexec.RemoteLocalFallbackExecStrategy)) pctx.VariableFunc("RETurbineExecStrategy", remoteexec.EnvOverrideFunc("RBE_TURBINE_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) pctx.VariableFunc("RESignApkExecStrategy", remoteexec.EnvOverrideFunc("RBE_SIGNAPK_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) pctx.VariableFunc("REJarExecStrategy", remoteexec.EnvOverrideFunc("RBE_JAR_EXEC_STRATEGY", remoteexec.LocalExecStrategy)) diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 9191a8321..40a2280d9 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -19,6 +19,7 @@ import ( "io" "android/soong/android" + "android/soong/dexpreopt" ) type DeviceHostConverter struct { @@ -162,7 +163,7 @@ func (d *DeviceHostConverter) AidlIncludeDirs() android.Paths { return nil } -func (d *DeviceHostConverter) ExportedSdkLibs() []string { +func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.LibraryPaths { return nil } diff --git a/java/dex.go b/java/dex.go index cd45a9319..21a59266e 100644 --- a/java/dex.go +++ b/java/dex.go @@ -38,6 +38,10 @@ type DexProperties struct { // True if the module containing this has it set by default. EnabledByDefault bool `blueprint:"mutated"` + // If true, runs R8 in Proguard compatibility mode (default). + // Otherwise, runs R8 in full mode. + Proguard_compatibility *bool + // If true, optimize for size by removing unused code. Defaults to true for apps, // false for libraries and tests. Shrink *bool @@ -72,6 +76,7 @@ type dexer struct { // list of extra proguard flag files extraProguardFlagFiles android.Paths proguardDictionary android.OptionalPath + proguardUsageZip android.OptionalPath } func (d *dexer) effectiveOptimizeEnabled() bool { @@ -109,13 +114,16 @@ var d8, d8RE = remoteexec.MultiCommandStaticRules(pctx, "d8", var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + - `rm -f "$outDict" && ` + + `rm -f "$outDict" && rm -rf "${outUsageDir}" && ` + + `mkdir -p $$(dirname ${outUsage}) && ` + `$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` + - `--force-proguard-compatibility ` + `--no-data-resources ` + - `-printmapping $outDict ` + + `-printmapping ${outDict} ` + + `-printusage ${outUsage} ` + `$r8Flags && ` + - `touch "$outDict" && ` + + `touch "${outDict}" "${outUsage}" && ` + + `${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` + + `rm -rf ${outUsageDir} && ` + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`, CommandDeps: []string{ @@ -138,7 +146,15 @@ var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8", ExecStrategy: "${config.RER8ExecStrategy}", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, - }, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"}) + "$zipUsageTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "${outUsage}"}, + OutputFiles: []string{"${outUsageZip}"}, + ExecStrategy: "${config.RER8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir", + "r8Flags", "zipFlags"}, []string{"implicits"}) func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion sdkSpec) []string { flags := d.dexProperties.Dxflags @@ -217,6 +233,10 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl r8Flags = append(r8Flags, opt.Proguard_flags...) + if BoolDefault(opt.Proguard_compatibility, true) { + r8Flags = append(r8Flags, "--force-proguard-compatibility") + } + // TODO(ccross): Don't shrink app instrumentation tests by default. if !Bool(opt.Shrink) { r8Flags = append(r8Flags, "-dontshrink") @@ -259,31 +279,39 @@ func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, mi if useR8 { proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary") d.proguardDictionary = android.OptionalPathForPath(proguardDictionary) + proguardUsageDir := android.PathForModuleOut(ctx, "proguard_usage") + proguardUsage := proguardUsageDir.Join(ctx, ctx.Namespace().Path, + android.ModuleNameWithPossibleOverride(ctx), "unused.txt") + proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip") + d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip) r8Flags, r8Deps := d.r8Flags(ctx, flags) rule := r8 args := map[string]string{ - "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "), - "zipFlags": zipFlags, - "outDict": proguardDictionary.String(), - "outDir": outDir.String(), + "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "), + "zipFlags": zipFlags, + "outDict": proguardDictionary.String(), + "outUsageDir": proguardUsageDir.String(), + "outUsage": proguardUsage.String(), + "outUsageZip": proguardUsageZip.String(), + "outDir": outDir.String(), } - if ctx.Config().IsEnvTrue("RBE_R8") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") { rule = r8RE args["implicits"] = strings.Join(r8Deps.Strings(), ",") } ctx.Build(pctx, android.BuildParams{ - Rule: rule, - Description: "r8", - Output: javalibJar, - ImplicitOutput: proguardDictionary, - Input: classesJar, - Implicits: r8Deps, - Args: args, + Rule: rule, + Description: "r8", + Output: javalibJar, + ImplicitOutputs: android.WritablePaths{proguardDictionary, proguardUsageZip}, + Input: classesJar, + Implicits: r8Deps, + Args: args, }) } else { d8Flags, d8Deps := d8Flags(flags) rule := d8 - if ctx.Config().IsEnvTrue("RBE_D8") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") { rule = d8RE } ctx.Build(pctx, android.BuildParams{ diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 2a84f14dc..3addc1a74 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -262,7 +262,7 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul apex, isApexModule := module.(android.ApexModule) fromUpdatableApex := isApexModule && apex.Updatable() if image.name == artBootImageName { - if isApexModule && strings.HasPrefix(apex.ApexVariationName(), "com.android.art.") { + if isApexModule && len(apex.InApexes()) > 0 && allHavePrefix(apex.InApexes(), "com.android.art.") { // ok: found the jar in the ART apex } else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) { // exception (skip and continue): special "hostdex" platform variant @@ -272,17 +272,17 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul return -1, nil } else if fromUpdatableApex { // error: this jar is part of an updatable apex other than ART - ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexVariationName()) + ctx.Errorf("module %q from updatable apexes %q is not allowed in the ART boot image", name, apex.InApexes()) } else { // error: this jar is part of the platform or a non-updatable apex - ctx.Errorf("module '%s' is not allowed in the ART boot image", name) + ctx.Errorf("module %q is not allowed in the ART boot image", name) } } else if image.name == frameworkBootImageName { if !fromUpdatableApex { // ok: this jar is part of the platform or a non-updatable apex } else { // error: this jar is part of an updatable apex - ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexVariationName()) + ctx.Errorf("module %q from updatable apexes %q is not allowed in the framework boot image", name, apex.InApexes()) } } else { panic("unknown boot image: " + image.name) @@ -291,6 +291,15 @@ func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, modul return index, jar.DexJarBuildPath() } +func allHavePrefix(list []string, prefix string) bool { + for _, s := range list { + if !strings.HasPrefix(s, prefix) { + return false + } + } + return true +} + // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image. func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig { // Collect dex jar paths for the boot image modules. diff --git a/java/droiddoc.go b/java/droiddoc.go index 4c5f66c18..e39a556e7 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -70,10 +70,6 @@ type JavadocProperties struct { // or .aidl files. Srcs []string `android:"path,arch_variant"` - // list of directories rooted at the Android.bp file that will - // be added to the search paths for finding source files when passing package names. - Local_sourcepaths []string - // list of source files that should not be used to build the Java module. // This is most useful in the arch/multilib variants to remove non-common files // filegroup or genrule can be included within this property. @@ -175,10 +171,6 @@ type DroiddocProperties struct { // resources output directory under out/soong/.intermediates. Resourcesoutdir *string - // if set to true, collect the values used by the Dev tools and - // write them in files packaged with the SDK. Defaults to false. - Write_sdk_values *bool - // index.html under current module will be copied to docs out dir, if not null. Static_doc_index_redirect *string `android:"path"` @@ -189,28 +181,6 @@ type DroiddocProperties struct { // filegroup or genrule can be included within this property. Knowntags []string `android:"path"` - // the generated public API filename by Doclava. - Api_filename *string - - // the generated removed API filename by Doclava. - Removed_api_filename *string - - // the generated removed Dex API filename by Doclava. - Removed_dex_api_filename *string - - // if set to false, don't allow droiddoc to generate stubs source files. Defaults to false. - Create_stubs *bool - - Check_api struct { - Last_released ApiToCheck - - Current ApiToCheck - - // do not perform API check against Last_released, in the case that both two specified API - // files by Last_released are modules which don't exist. - Ignore_missing_latest_api *bool `blueprint:"mutated"` - } - // if set to true, generate docs through Dokka instead of Doclava. Dokka_enabled *bool @@ -219,10 +189,10 @@ type DroiddocProperties struct { } type DroidstubsProperties struct { - // the generated public API filename by Metalava. + // The generated public API filename by Metalava, defaults to <module>_api.txt Api_filename *string - // the generated removed API filename by Metalava. + // the generated removed API filename by Metalava, defaults to <module>_removed.txt Removed_api_filename *string // the generated removed Dex API filename by Metalava. @@ -639,10 +609,9 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { j.srcFiles = srcFiles.FilterOutByExt(".srcjar") j.srcFiles = append(j.srcFiles, deps.srcs...) - if j.properties.Local_sourcepaths == nil && len(j.srcFiles) > 0 { - j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".") + if len(j.srcFiles) > 0 { + j.sourcepaths = android.PathsForModuleSrc(ctx, []string{"."}) } - j.sourcepaths = android.PathsForModuleSrc(ctx, j.properties.Local_sourcepaths) j.argFiles = android.PathsForModuleSrc(ctx, j.properties.Arg_files) argFilesMap := map[string]string{} @@ -748,17 +717,7 @@ func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { type Droiddoc struct { Javadoc - properties DroiddocProperties - apiFile android.WritablePath - privateApiFile android.WritablePath - removedApiFile android.WritablePath - removedDexApiFile android.WritablePath - - checkCurrentApiTimestamp android.WritablePath - updateCurrentApiTimestamp android.WritablePath - checkLastReleasedApiTimestamp android.WritablePath - - apiFilePath android.Path + properties DroiddocProperties } // droiddoc converts .java source files to documentation using doclava or dokka. @@ -783,17 +742,18 @@ func DroiddocHostFactory() android.Module { return module } -func (d *Droiddoc) ApiFilePath() android.Path { - return d.apiFilePath +func (d *Droiddoc) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "", ".docs.zip": + return android.Paths{d.Javadoc.docZip}, nil + default: + return nil, fmt.Errorf("unsupported module reference tag %q", tag) + } } func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) { d.Javadoc.addDeps(ctx) - if Bool(d.properties.Check_api.Ignore_missing_latest_api) { - ignoreMissingModules(ctx, &d.properties.Check_api.Last_released) - } - if String(d.properties.Custom_template) != "" { ctx.AddDependency(ctx.Module(), droiddocTemplateTag, String(d.properties.Custom_template)) } @@ -873,41 +833,6 @@ func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.Rule } } -func (d *Droiddoc) createStubs() bool { - return BoolDefault(d.properties.Create_stubs, false) -} - -func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) { - if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || - apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || - String(d.properties.Api_filename) != "" { - - d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt") - cmd.FlagWithOutput("-api ", d.apiFile) - d.apiFilePath = d.apiFile - } - - if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || - apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || - String(d.properties.Removed_api_filename) != "" { - d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt") - cmd.FlagWithOutput("-removedApi ", d.removedApiFile) - } - - if String(d.properties.Removed_dex_api_filename) != "" { - d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename)) - cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile) - } - - if d.createStubs() { - cmd.FlagWithArg("-stubs ", stubsDir.String()) - } - - if Bool(d.properties.Write_sdk_values) { - cmd.FlagWithArg("-sdkvalues ", android.PathForModuleOut(ctx, "out").String()) - } -} - func (d *Droiddoc) postDoclavaCmds(ctx android.ModuleContext, rule *android.RuleBuilder) { if String(d.properties.Static_doc_index_redirect) != "" { staticDocIndexRedirect := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_index_redirect)) @@ -1010,22 +935,15 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { deps := d.Javadoc.collectDeps(ctx) d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip") - d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar") jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar") doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar") - java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME") - checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")} outDir := android.PathForModuleOut(ctx, "out") srcJarDir := android.PathForModuleOut(ctx, "srcjars") - stubsDir := android.PathForModuleOut(ctx, "stubsDir") rule := android.NewRuleBuilder() - rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String()) - rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String()) - srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars) var cmd *android.RuleBuilderCommand @@ -1036,8 +954,6 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths) } - d.stubsFlags(ctx, cmd, stubsDir) - cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles) if d.properties.Compat_config != nil { @@ -1067,120 +983,11 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { FlagWithArg("-C ", outDir.String()). FlagWithArg("-D ", outDir.String()) - rule.Command(). - BuiltTool(ctx, "soong_zip"). - Flag("-write_if_changed"). - Flag("-jar"). - FlagWithOutput("-o ", d.stubsSrcJar). - FlagWithArg("-C ", stubsDir.String()). - FlagWithArg("-D ", stubsDir.String()) - rule.Restat() zipSyncCleanupCmd(rule, srcJarDir) rule.Build(pctx, ctx, "javadoc", desc) - - if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { - apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file)) - removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file)) - - d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp") - - rule := android.NewRuleBuilder() - - rule.Command().Text("( true") - - rule.Command(). - BuiltTool(ctx, "apicheck"). - Flag("-JXmx1024m"). - FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":"). - OptionalFlag(d.properties.Check_api.Current.Args). - Input(apiFile). - Input(d.apiFile). - Input(removedApiFile). - Input(d.removedApiFile) - - msg := fmt.Sprintf(`\n******************************\n`+ - `You have tried to change the API from what has been previously approved.\n\n`+ - `To make these errors go away, you have two choices:\n`+ - ` 1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+ - ` errors above.\n\n`+ - ` 2. You can update current.txt by executing the following command:\n`+ - ` make %s-update-current-api\n\n`+ - ` To submit the revised current.txt to the main Android repository,\n`+ - ` you will need approval.\n`+ - `******************************\n`, ctx.ModuleName()) - - rule.Command(). - Text("touch").Output(d.checkCurrentApiTimestamp). - Text(") || ("). - Text("echo").Flag("-e").Flag(`"` + msg + `"`). - Text("; exit 38"). - Text(")") - - rule.Build(pctx, ctx, "doclavaCurrentApiCheck", "check current API") - - d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp") - - // update API rule - rule = android.NewRuleBuilder() - - rule.Command().Text("( true") - - rule.Command(). - Text("cp").Flag("-f"). - Input(d.apiFile).Flag(apiFile.String()) - - rule.Command(). - Text("cp").Flag("-f"). - Input(d.removedApiFile).Flag(removedApiFile.String()) - - msg = "failed to update public API" - - rule.Command(). - Text("touch").Output(d.updateCurrentApiTimestamp). - Text(") || ("). - Text("echo").Flag("-e").Flag(`"` + msg + `"`). - Text("; exit 38"). - Text(")") - - rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API") - } - - if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") { - apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file)) - removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file)) - - d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp") - - rule := android.NewRuleBuilder() - - rule.Command(). - Text("("). - BuiltTool(ctx, "apicheck"). - Flag("-JXmx1024m"). - FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":"). - OptionalFlag(d.properties.Check_api.Last_released.Args). - Input(apiFile). - Input(d.apiFile). - Input(removedApiFile). - Input(d.removedApiFile) - - msg := `\n******************************\n` + - `You have tried to change the API from what has been previously released in\n` + - `an SDK. Please fix the errors listed above.\n` + - `******************************\n` - - rule.Command(). - Text("touch").Output(d.checkLastReleasedApiTimestamp). - Text(") || ("). - Text("echo").Flag("-e").Flag(`"` + msg + `"`). - Text("; exit 38"). - Text(")") - - rule.Build(pctx, ctx, "doclavaLastApiCheck", "check last API") - } } // @@ -1314,7 +1121,8 @@ func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuil if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || String(d.properties.Api_filename) != "" { - d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt") + filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt") + d.apiFile = android.PathForModuleOut(ctx, filename) cmd.FlagWithOutput("--api ", d.apiFile) d.apiFilePath = d.apiFile } @@ -1322,7 +1130,8 @@ func (d *Droidstubs) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuil if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") || apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") || String(d.properties.Removed_api_filename) != "" { - d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt") + filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt") + d.removedApiFile = android.PathForModuleOut(ctx, filename) cmd.FlagWithOutput("--removed-api ", d.removedApiFile) } @@ -1464,7 +1273,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi // Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel. rule.HighMem() cmd := rule.Command() - if ctx.Config().IsEnvTrue("RBE_METALAVA") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") { rule.Remoteable(android.RemoteRuleSupports{RBE: true}) pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava") execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy) @@ -1600,6 +1409,15 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { d.apiLintReport = android.PathForModuleOut(ctx, "api_lint_report.txt") cmd.FlagWithOutput("--report-even-if-suppressed ", d.apiLintReport) // TODO: Change to ":api-lint" + // TODO(b/154317059): Clean up this whitelist by baselining and/or checking in last-released. + if d.Name() != "android.car-system-stubs-docs" && + d.Name() != "android.car-stubs-docs" && + d.Name() != "system-api-stubs-docs" && + d.Name() != "test-api-stubs-docs" { + cmd.Flag("--lints-as-errors") + cmd.Flag("--warnings-as-errors") // Most lints are actually warnings. + } + baselineFile := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.Baseline_file) updatedBaselineOutput := android.PathForModuleOut(ctx, "api_lint_baseline.txt") d.apiLintTimestamp = android.PathForModuleOut(ctx, "api_lint.timestamp") diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index ea3fbdade..b6af3bf28 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -163,6 +163,7 @@ func stubFlagsRule(ctx android.SingletonContext) { return } } + bootDexJars = append(bootDexJars, jar) } } @@ -207,6 +208,15 @@ func stubFlagsRule(ctx android.SingletonContext) { rule.Build(pctx, ctx, "hiddenAPIStubFlagsFile", "hiddenapi stub flags") } +func moduleForGreyListRemovedApis(ctx android.SingletonContext, module android.Module) bool { + switch ctx.ModuleName(module) { + case "api-stubs-docs", "system-api-stubs-docs", "android.car-stubs-docs", "android.car-system-stubs-docs": + return true + default: + return false + } +} + // flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and // the unsupported API. func flagsRule(ctx android.SingletonContext) android.Path { @@ -222,7 +232,7 @@ func flagsRule(ctx android.SingletonContext) android.Path { // Track @removed public and system APIs via corresponding droidstubs targets. // These APIs are not present in the stubs, however, we have to keep allowing access // to them at runtime. - if m := ctx.ModuleName(module); m == "api-stubs-docs" || m == "system-api-stubs-docs" { + if moduleForGreyListRemovedApis(ctx, module) { greylistRemovedApis = append(greylistRemovedApis, ds.removedDexApiFile) } } diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go new file mode 100644 index 000000000..bcca93a00 --- /dev/null +++ b/java/hiddenapi_singleton_test.go @@ -0,0 +1,136 @@ +// 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 java + +import ( + "android/soong/android" + "strings" + "testing" +) + +func testConfigWithBootJars(bp string, bootJars []string) android.Config { + config := testConfig(nil, bp, nil) + config.TestProductVariables.BootJars = bootJars + return config +} + +func testContextWithHiddenAPI() *android.TestContext { + ctx := testContext() + ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory) + return ctx +} + +func testHiddenAPI(t *testing.T, bp string, bootJars []string) (*android.TestContext, android.Config) { + t.Helper() + + config := testConfigWithBootJars(bp, bootJars) + ctx := testContextWithHiddenAPI() + + run(t, ctx, config) + + return ctx, config +} + +func TestHiddenAPISingleton(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + `, []string{":foo"}) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, want) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + } + `, []string{":foo"}) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, want) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: false, + } + `, []string{":foo"}) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command) + } + + prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar" + if strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) { + t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command) + } +} + +func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { + ctx, _ := testHiddenAPI(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + compile_dex: true, + } + + java_import { + name: "foo", + jars: ["a.jar"], + compile_dex: true, + prefer: true, + } + `, []string{":foo"}) + + hiddenAPI := ctx.SingletonForTests("hiddenapi") + hiddenapiRule := hiddenAPI.Rule("hiddenapi") + prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/prebuilt_foo/android_common/dex/foo.jar" + if !strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) { + t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command) + } + + fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar" + if strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) { + t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command) + } +} diff --git a/java/java.go b/java/java.go index 10c6fd369..d67e9e098 100644 --- a/java/java.go +++ b/java/java.go @@ -29,6 +29,7 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/dexpreopt" "android/soong/java/config" "android/soong/tradefed" ) @@ -323,6 +324,10 @@ type CompilerDeviceProperties struct { Stem *string IsSDKLibrary bool `blueprint:"mutated"` + + // If true, generate the signature file of APK Signing Scheme V4, along side the signed APK file. + // Defaults to false. + V4_signature *bool } // Functionality common to Module and Import @@ -411,8 +416,8 @@ type Module struct { // manifest file to use instead of properties.Manifest overrideManifest android.OptionalPath - // list of SDK lib names that this java module is exporting - exportedSdkLibs []string + // map of SDK libs exported by this java module to their build and install paths + exportedSdkLibs dexpreopt.LibraryPaths // list of plugins that this java module is exporting exportedPluginJars android.Paths @@ -436,6 +441,7 @@ type Module struct { hiddenAPI dexer dexpreopter + usesLibrary linter // list of the xref extraction files @@ -451,6 +457,7 @@ func (j *Module) addHostProperties() { j.AddProperties( &j.properties, &j.protoProperties, + &j.usesLibraryProperties, ) } @@ -488,14 +495,19 @@ type ApexDependency interface { ImplementationAndResourcesJars() android.Paths } +// Provides build path and install path to DEX jars. +type UsesLibraryDependency interface { + DexJarBuildPath() android.Path + DexJarInstallPath() android.Path +} + type Dependency interface { ApexDependency + UsesLibraryDependency ImplementationJars() android.Paths ResourceJars() android.Paths - DexJarBuildPath() android.Path - DexJarInstallPath() android.Path AidlIncludeDirs() android.Paths - ExportedSdkLibs() []string + ExportedSdkLibs() dexpreopt.LibraryPaths ExportedPlugins() (android.Paths, []string) SrcJarArgs() ([]string, android.Paths) BaseModuleName() string @@ -552,7 +564,6 @@ var ( bootClasspathTag = dependencyTag{name: "bootclasspath"} systemModulesTag = dependencyTag{name: "system modules"} frameworkResTag = dependencyTag{name: "framework-res"} - frameworkApkTag = dependencyTag{name: "framework-apk"} kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"} kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations"} proguardRaiseTag = dependencyTag{name: "proguard-raise"} @@ -674,31 +685,29 @@ func (j *Module) AvailableFor(what string) bool { return j.ApexModuleBase.AvailableFor(what) } +func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext sdkContext, d dexer) { + sdkDep := decodeSdkDep(ctx, sdkContext) + if sdkDep.useModule { + ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) + ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) + ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...) + if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() { + ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...) + } + if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() { + ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...) + } + } + if sdkDep.systemModules != "" { + ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) + } +} + func (j *Module) deps(ctx android.BottomUpMutatorContext) { if ctx.Device() { j.linter.deps(ctx) - sdkDep := decodeSdkDep(ctx, sdkContext(j)) - if sdkDep.useModule { - ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) - ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...) - ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...) - if j.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() { - ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...) - } - if j.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() { - ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...) - } - } - if sdkDep.systemModules != "" { - ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) - } - - if ctx.ModuleName() == "android_stubs_current" || - ctx.ModuleName() == "android_system_stubs_current" || - ctx.ModuleName() == "android_test_stubs_current" { - ctx.AddVariationDependencies(nil, frameworkApkTag, "framework-res") - } + sdkDeps(ctx, sdkContext(j), j.dexer) } syspropPublicStubs := syspropPublicStubs(ctx.Config()) @@ -973,12 +982,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } } - // If this is a component library (stubs, etc.) for a java_sdk_library then - // add the name of that java_sdk_library to the exported sdk libs to make sure - // that, if necessary, a <uses-library> element for that java_sdk_library is - // added to the Android manifest. - j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) - ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -998,7 +1001,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag: deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...) + j.exportedSdkLibs.MaybeAddLibraryPath(ctx, dep.OptionalImplicitSdkLibrary(), dep.DexJarBuildPath(), dep.DexJarInstallPath()) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } @@ -1009,7 +1012,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case libTag, instrumentationForTag: deps.classpath = append(deps.classpath, dep.HeaderJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) pluginJars, pluginClasses := dep.ExportedPlugins() addPlugins(&deps, pluginJars, pluginClasses...) @@ -1021,7 +1024,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...) deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...) pluginJars, pluginClasses := dep.ExportedPlugins() addPlugins(&deps, pluginJars, pluginClasses...) @@ -1048,18 +1051,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } else { ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName) } - case frameworkApkTag: - if ctx.ModuleName() == "android_stubs_current" || - ctx.ModuleName() == "android_system_stubs_current" || - ctx.ModuleName() == "android_test_stubs_current" { - // framework stubs.jar need to depend on framework-res.apk, in order to pull the - // resource files out of there for aapt. - // - // Normally the package rule runs aapt, which includes the resource, - // but we're not running that in our package rule so just copy in the - // resource files here. - deps.staticResourceJars = append(deps.staticResourceJars, dep.(*AndroidApp).exportPackage) - } case kotlinStdlibTag: deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...) case kotlinAnnotationsTag: @@ -1096,8 +1087,6 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } }) - j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs) - return deps } @@ -1504,7 +1493,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { args := map[string]string{ "jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "), } - if ctx.Config().IsEnvTrue("RBE_ZIP") { + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ZIP") { rule = zipRE args["implicits"] = strings.Join(services.Strings(), ",") } @@ -1625,6 +1614,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { configurationName := j.ConfigurationName() primary := configurationName == ctx.ModuleName() + // If the prebuilt is being used rather than the from source, skip this + // module to prevent duplicated classes + primary = primary && !j.IsReplacedByPrebuilt() // Hidden API CSV generation and dex encoding dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile, @@ -1838,8 +1830,7 @@ func (j *Module) AidlIncludeDirs() android.Paths { return j.exportAidlIncludeDirs } -func (j *Module) ExportedSdkLibs() []string { - // exportedSdkLibs is type []string +func (j *Module) ExportedSdkLibs() dexpreopt.LibraryPaths { return j.exportedSdkLibs } @@ -1972,6 +1963,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter)) } j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex + j.exportedSdkLibs = make(dexpreopt.LibraryPaths) j.compile(ctx, nil) // Collect the module directory for IDE info in java/jdeps.go. @@ -1987,6 +1979,17 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.Stem()+".jar", j.outputFile, extraInstallDeps...) } + // If this is a component library (stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a <uses-library> element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), j.DexJarBuildPath(), j.DexJarInstallPath()) + + // A non-SDK library may provide a <uses-library> (the name may be different from the module name). + if lib := proptools.String(j.usesLibraryProperties.Provides_uses_lib); lib != "" { + j.exportedSdkLibs.AddLibraryPath(ctx, lib, j.DexJarBuildPath(), j.DexJarInstallPath()) + } + j.distFiles = j.GenerateTaggedDistFiles(ctx) } @@ -2139,6 +2142,12 @@ func LibraryHostFactory() android.Module { // Java Tests // +// Test option struct. +type TestOptions struct { + // a list of extra test configuration files that should be installed with the module. + Extra_test_configs []string `android:"path,arch_variant"` +} + type testProperties struct { // list of compatibility suites (for example "cts", "vts") that the module should be // installed into. @@ -2164,6 +2173,9 @@ type testProperties struct { // Add parameterized mainline modules to auto generated test config. The options will be // handled by TradeFed to do downloading and installing the specified modules on the device. Test_mainline_modules []string + + // Test options. + Test_options TestOptions } type hostTestProperties struct { @@ -2192,8 +2204,9 @@ type Test struct { testProperties testProperties - testConfig android.Path - data android.Paths + testConfig android.Path + extraTestConfigs android.Paths + data android.Paths } type TestHost struct { @@ -2214,6 +2227,7 @@ type JavaTestImport struct { prebuiltTestProperties prebuiltTestProperties testConfig android.Path + dexJarFile android.Path } func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -2232,6 +2246,8 @@ func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data) + j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs) + ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) { j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) }) @@ -2534,10 +2550,16 @@ type Import struct { // Functionality common to Module and Import. embeddableInModuleAndImport + hiddenAPI + dexer + properties ImportProperties + // output file containing classes.dex and resources + dexJarFile android.Path + combinedClasspathFile android.Path - exportedSdkLibs []string + exportedSdkLibs dexpreopt.LibraryPaths exportAidlIncludeDirs android.Paths } @@ -2545,10 +2567,22 @@ func (j *Import) sdkVersion() sdkSpec { return sdkSpecFrom(String(j.properties.Sdk_version)) } +func (j *Import) makeSdkVersion() string { + return j.sdkVersion().raw +} + +func (j *Import) systemModules() string { + return "none" +} + func (j *Import) minSdkVersion() sdkSpec { return j.sdkVersion() } +func (j *Import) targetSdkVersion() sdkSpec { + return j.sdkVersion() +} + func (j *Import) MinSdkVersion() string { return j.minSdkVersion().version.String() } @@ -2575,6 +2609,10 @@ func (a *Import) JacocoReportClassesFile() android.Path { func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) + + if ctx.Device() && Bool(j.dexProperties.Compile_dex) { + sdkDeps(ctx, sdkContext(j), j.dexer) + } } func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -2590,12 +2628,9 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { TransformJetifier(ctx, outputFile, inputFile) } j.combinedClasspathFile = outputFile + j.exportedSdkLibs = make(dexpreopt.LibraryPaths) - // If this is a component library (impl, stubs, etc.) for a java_sdk_library then - // add the name of that java_sdk_library to the exported sdk libs to make sure - // that, if necessary, a <uses-library> element for that java_sdk_library is - // added to the Android manifest. - j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...) + var flags javaBuilderFlags ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) @@ -2605,25 +2640,62 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { case Dependency: switch tag { case libTag, staticLibTag: + flags.classpath = append(flags.classpath, dep.HeaderJars()...) // sdk lib names from dependencies are re-exported - j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...) + j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs()) + case bootClasspathTag: + flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...) } case SdkLibraryDependency: switch tag { case libTag: + flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) // names of sdk libs that are directly depended are exported - j.exportedSdkLibs = append(j.exportedSdkLibs, otherName) + j.exportedSdkLibs.AddLibraryPath(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath()) } } }) - j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs) + var installFile android.Path if Bool(j.properties.Installable) { - ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), + installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), jarName, outputFile) } + // If this is a component library (impl, stubs, etc.) for a java_sdk_library then + // add the name of that java_sdk_library to the exported sdk libs to make sure + // that, if necessary, a <uses-library> element for that java_sdk_library is + // added to the Android manifest. + j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), outputFile, installFile) + j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs) + + if ctx.Device() && Bool(j.dexProperties.Compile_dex) { + sdkDep := decodeSdkDep(ctx, sdkContext(j)) + if sdkDep.invalidVersion { + ctx.AddMissingDependencies(sdkDep.bootclasspath) + ctx.AddMissingDependencies(sdkDep.java9Classpath) + } else if sdkDep.useFiles { + // sdkDep.jar is actually equivalent to turbine header.jar. + flags.classpath = append(flags.classpath, sdkDep.jars...) + } + + // Dex compilation + var dexOutputFile android.ModuleOutPath + dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName) + if ctx.Failed() { + return + } + + configurationName := j.BaseModuleName() + primary := j.Prebuilt().UsePrebuilt() + + // Hidden API CSV generation and dex encoding + dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, outputFile, + proptools.Bool(j.dexProperties.Uncompress_dex)) + + j.dexJarFile = dexOutputFile + } } var _ Dependency = (*Import)(nil) @@ -2654,7 +2726,7 @@ func (j *Import) ImplementationAndResourcesJars() android.Paths { } func (j *Import) DexJarBuildPath() android.Path { - return nil + return j.dexJarFile } func (j *Import) DexJarInstallPath() android.Path { @@ -2665,7 +2737,7 @@ func (j *Import) AidlIncludeDirs() android.Paths { return j.exportAidlIncludeDirs } -func (j *Import) ExportedSdkLibs() []string { +func (j *Import) ExportedSdkLibs() dexpreopt.LibraryPaths { return j.exportedSdkLibs } @@ -2722,10 +2794,15 @@ var _ android.PrebuiltInterface = (*Import)(nil) func ImportFactory() android.Module { module := &Import{} - module.AddProperties(&module.properties) + module.AddProperties( + &module.properties, + &module.dexer.dexProperties, + ) module.initModuleAndImport(&module.ModuleBase) + module.dexProperties.Optimize.EnabledByDefault = false + android.InitPrebuiltModule(module, &module.properties.Jars) android.InitApexModule(module) android.InitSdkAwareModule(module) diff --git a/java/java_test.go b/java/java_test.go index 50c40c38c..9e6357792 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -20,7 +20,6 @@ import ( "path/filepath" "reflect" "regexp" - "sort" "strconv" "strings" "testing" @@ -526,6 +525,8 @@ func TestPrebuilts(t *testing.T) { java_import { name: "baz", jars: ["b.jar"], + sdk_version: "current", + compile_dex: true, } dex_import { @@ -556,8 +557,10 @@ func TestPrebuilts(t *testing.T) { fooModule := ctx.ModuleForTests("foo", "android_common") javac := fooModule.Rule("javac") combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac") - barJar := ctx.ModuleForTests("bar", "android_common").Rule("combineJar").Output - bazJar := ctx.ModuleForTests("baz", "android_common").Rule("combineJar").Output + barModule := ctx.ModuleForTests("bar", "android_common") + barJar := barModule.Rule("combineJar").Output + bazModule := ctx.ModuleForTests("baz", "android_common") + bazJar := bazModule.Rule("combineJar").Output sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common").Rule("combineJar").Output fooLibrary := fooModule.Module().(*Library) @@ -572,6 +575,11 @@ func TestPrebuilts(t *testing.T) { t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String()) } + barDexJar := barModule.Module().(*Import).DexJarBuildPath() + if barDexJar != nil { + t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar) + } + if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) { t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String()) } @@ -580,6 +588,12 @@ func TestPrebuilts(t *testing.T) { t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String()) } + bazDexJar := bazModule.Module().(*Import).DexJarBuildPath().String() + expectedDexJar := buildDir + "/.intermediates/baz/android_common/dex/baz.jar" + if bazDexJar != expectedDexJar { + t.Errorf("baz dex jar build path expected %q, got %q", expectedDexJar, bazDexJar) + } + ctx.ModuleForTests("qux", "android_common").Rule("Cp") } @@ -1083,16 +1097,26 @@ func TestDroiddoc(t *testing.T) { srcs: ["bar-doc/IBar.aidl"], path: "bar-doc", } - droiddoc { - name: "bar-doc", + droidstubs { + name: "bar-stubs", srcs: [ "bar-doc/a.java", - "bar-doc/IFoo.aidl", - ":bar-doc-aidl-srcs", ], exclude_srcs: [ "bar-doc/b.java" ], + api_levels_annotations_dirs: [ + "droiddoc-templates-sdk", + ], + api_levels_annotations_enabled: true, + } + droiddoc { + name: "bar-doc", + srcs: [ + ":bar-stubs", + "bar-doc/IFoo.aidl", + ":bar-doc-aidl-srcs", + ], custom_template: "droiddoc-templates-sdk", hdf: [ "android.whichdoc offline", @@ -1109,23 +1133,29 @@ func TestDroiddoc(t *testing.T) { "bar-doc/a.java": nil, "bar-doc/b.java": nil, }) - barDocModule := ctx.ModuleForTests("bar-doc", "android_common") - barDoc := barDocModule.Rule("javadoc") - notExpected := " -stubs " - if strings.Contains(barDoc.RuleParams.Command, notExpected) { - t.Errorf("bar-doc command contains flag %q to create stubs, but should not", notExpected) + barStubs := ctx.ModuleForTests("bar-stubs", "android_common") + barStubsOutputs, err := barStubs.Module().(*Droidstubs).OutputFiles("") + if err != nil { + t.Errorf("Unexpected error %q retrieving \"bar-stubs\" output file", err) + } + if len(barStubsOutputs) != 1 { + t.Errorf("Expected one output from \"bar-stubs\" got %s", barStubsOutputs) } - var javaSrcs []string - for _, i := range barDoc.Inputs { - javaSrcs = append(javaSrcs, i.Base()) + barStubsOutput := barStubsOutputs[0] + barDoc := ctx.ModuleForTests("bar-doc", "android_common") + javaDoc := barDoc.Rule("javadoc") + if g, w := javaDoc.Implicits.Strings(), barStubsOutput.String(); !inList(w, g) { + t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g) } - if len(javaSrcs) != 1 || javaSrcs[0] != "a.java" { - t.Errorf("inputs of bar-doc must be []string{\"a.java\"}, but was %#v.", javaSrcs) + + expected := "-sourcepath " + buildDir + "/.intermediates/bar-doc/android_common/srcjars " + if !strings.Contains(javaDoc.RuleParams.Command, expected) { + t.Errorf("bar-doc command does not contain flag %q, but should\n%q", expected, javaDoc.RuleParams.Command) } - aidl := barDocModule.Rule("aidl") - if g, w := barDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) { + aidl := barDoc.Rule("aidl") + if g, w := javaDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) { t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g) } @@ -1145,16 +1175,26 @@ func TestDroiddocArgsAndFlagsCausesError(t *testing.T) { srcs: ["bar-doc/IBar.aidl"], path: "bar-doc", } - droiddoc { - name: "bar-doc", + droidstubs { + name: "bar-stubs", srcs: [ "bar-doc/a.java", - "bar-doc/IFoo.aidl", - ":bar-doc-aidl-srcs", ], exclude_srcs: [ "bar-doc/b.java" ], + api_levels_annotations_dirs: [ + "droiddoc-templates-sdk", + ], + api_levels_annotations_enabled: true, + } + droiddoc { + name: "bar-doc", + srcs: [ + ":bar-stubs", + "bar-doc/IFoo.aidl", + ":bar-doc-aidl-srcs", + ], custom_template: "droiddoc-templates-sdk", hdf: [ "android.whichdoc offline", @@ -1496,8 +1536,7 @@ func TestJavaSdkLibrary(t *testing.T) { // test if baz has exported SDK lib names foo and bar to qux qux := ctx.ModuleForTests("qux", "android_common") if quxLib, ok := qux.Module().(*Library); ok { - sdkLibs := quxLib.ExportedSdkLibs() - sort.Strings(sdkLibs) + sdkLibs := android.SortedStringKeys(quxLib.ExportedSdkLibs()) if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) { t.Errorf("qux should export %q but exports %q", w, sdkLibs) } diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go index 8af66d098..021920af6 100644 --- a/java/legacy_core_platform_api_usage.go +++ b/java/legacy_core_platform_api_usage.go @@ -19,6 +19,10 @@ import ( "android/soong/java/config" ) +// This variable is effectively unused in pre-master branches, and is +// included (with the same value as it has in AOSP) only to ease +// merges between branches (see the comment in the +// useLegacyCorePlatformApi() function): var legacyCorePlatformApiModules = []string{ "ahat-test-dump", "android.car", @@ -132,6 +136,10 @@ var legacyCorePlatformApiModules = []string{ "wifi-service", } +// This variable is effectively unused in pre-master branches, and is +// included (with the same value as it has in AOSP) only to ease +// merges between branches (see the comment in the +// useLegacyCorePlatformApi() function): var legacyCorePlatformApiLookup = make(map[string]struct{}) func init() { @@ -141,8 +149,12 @@ func init() { } func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool { - _, found := legacyCorePlatformApiLookup[ctx.ModuleName()] - return found + // In pre-master branches, we don't attempt to force usage of the stable + // version of the core/platform API. Instead, we always use the legacy + // version --- except in tests, where we always use stable, so that we + // can make the test assertions the same as other branches. + // This should be false in tests and true otherwise: + return ctx.Config().TestProductVariables == nil } func corePlatformSystemModules(ctx android.EarlyModuleContext) string { diff --git a/java/lint.go b/java/lint.go index b37f69265..3a210cc0b 100644 --- a/java/lint.go +++ b/java/lint.go @@ -513,7 +513,7 @@ func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android rule.Command().BuiltTool(ctx, "soong_zip"). FlagWithOutput("-o ", outputPath). FlagWithArg("-C ", android.PathForIntermediates(ctx).String()). - FlagWithRspFileInputList("-l ", paths) + FlagWithRspFileInputList("-r ", paths) rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base()) } diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go index b10e6c7fe..bcc6cc0cf 100644 --- a/java/prebuilt_apis.go +++ b/java/prebuilt_apis.go @@ -34,6 +34,13 @@ func RegisterPrebuiltApisBuildComponents(ctx android.RegistrationContext) { type prebuiltApisProperties struct { // list of api version directories Api_dirs []string + + // The sdk_version of java_import modules generated based on jar files. + // Defaults to "current" + Imports_sdk_version *string + + // If set to true, compile dex for java_import modules. Defaults to false. + Imports_compile_dex *bool } type prebuiltApis struct { @@ -74,17 +81,19 @@ func prebuiltApiModuleName(mctx android.LoadHookContext, module string, scope st return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module } -func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) { +func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdkVersion string, compileDex bool) { props := struct { Name *string Jars []string Sdk_version *string Installable *bool + Compile_dex *bool }{} props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver)) props.Jars = append(props.Jars, path) - props.Sdk_version = proptools.StringPtr(scope) + props.Sdk_version = proptools.StringPtr(sdkVersion) props.Installable = proptools.BoolPtr(false) + props.Compile_dex = proptools.BoolPtr(compileDex) mctx.CreateModule(ImportFactory, &props) } @@ -100,10 +109,10 @@ func createFilegroup(mctx android.LoadHookContext, module string, scope string, mctx.CreateModule(android.FileGroupFactory, &filegroupProps) } -func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { +func getPrebuiltFiles(mctx android.LoadHookContext, p *prebuiltApis, name string) []string { mydir := mctx.ModuleDir() + "/" var files []string - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { + for _, apiver := range p.properties.Api_dirs { for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} { vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil) if err != nil { @@ -115,16 +124,19 @@ func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string { return files } -func prebuiltSdkStubs(mctx android.LoadHookContext) { +func prebuiltSdkStubs(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/<module>.jar - files := getPrebuiltFiles(mctx, "*.jar") + files := getPrebuiltFiles(mctx, p, "*.jar") + + sdkVersion := proptools.StringDefault(p.properties.Imports_sdk_version, "current") + compileDex := proptools.BoolDefault(p.properties.Imports_compile_dex, false) for _, f := range files { // create a Import module for each jar file localPath := strings.TrimPrefix(f, mydir) module, apiver, scope := parseJarPath(localPath) - createImport(mctx, module, scope, apiver, localPath) + createImport(mctx, module, scope, apiver, localPath, sdkVersion, compileDex) } } @@ -139,8 +151,8 @@ func createSystemModules(mctx android.LoadHookContext, apiver string) { mctx.CreateModule(SystemModulesFactory, &props) } -func prebuiltSdkSystemModules(mctx android.LoadHookContext) { - for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs { +func prebuiltSdkSystemModules(mctx android.LoadHookContext, p *prebuiltApis) { + for _, apiver := range p.properties.Api_dirs { jar := android.ExistentPathForSource(mctx, mctx.ModuleDir(), apiver, "public", "core-for-system-modules.jar") if jar.Valid() { @@ -149,10 +161,10 @@ func prebuiltSdkSystemModules(mctx android.LoadHookContext) { } } -func prebuiltApiFiles(mctx android.LoadHookContext) { +func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) { mydir := mctx.ModuleDir() + "/" // <apiver>/<scope>/api/<module>.txt - files := getPrebuiltFiles(mctx, "api/*.txt") + files := getPrebuiltFiles(mctx, p, "api/*.txt") if len(files) == 0 { mctx.ModuleErrorf("no api file found under %q", mydir) @@ -200,10 +212,10 @@ func prebuiltApiFiles(mctx android.LoadHookContext) { } func createPrebuiltApiModules(mctx android.LoadHookContext) { - if _, ok := mctx.Module().(*prebuiltApis); ok { - prebuiltApiFiles(mctx) - prebuiltSdkStubs(mctx) - prebuiltSdkSystemModules(mctx) + if p, ok := mctx.Module().(*prebuiltApis); ok { + prebuiltApiFiles(mctx, p) + prebuiltSdkStubs(mctx, p) + prebuiltSdkSystemModules(mctx, p) } } diff --git a/java/robolectric.go b/java/robolectric.go index 3fe6626bb..04fc11722 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -31,7 +31,6 @@ func init() { } var robolectricDefaultLibs = []string{ - "robolectric_android-all-stub", "Robolectric_all-target", "mockito-robolectric-prebuilt", "truth-prebuilt", @@ -99,7 +98,8 @@ func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...) - ctx.AddVariationDependencies(nil, roboRuntimesTag, "robolectric-android-all-prebuilts") + ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), + roboRuntimesTag, "robolectric-android-all-prebuilts") } func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -326,14 +326,16 @@ func RobolectricTestFactory() android.Module { return module } -func (r *robolectricTest) InstallBypassMake() bool { return true } -func (r *robolectricTest) InstallInTestcases() bool { return true } -func (r *robolectricTest) InstallForceOS() *android.OsType { return &android.BuildOs } +func (r *robolectricTest) InstallBypassMake() bool { return true } +func (r *robolectricTest) InstallInTestcases() bool { return true } +func (r *robolectricTest) InstallForceOS() (*android.OsType, *android.ArchType) { + return &android.BuildOs, &android.BuildArch +} func robolectricRuntimesFactory() android.Module { module := &robolectricRuntimes{} module.AddProperties(&module.props) - android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitAndroidArchModule(module, android.HostSupportedNoCross, android.MultilibCommon) return module } @@ -363,6 +365,10 @@ func (r *robolectricRuntimes) DepsMutator(ctx android.BottomUpMutatorContext) { } func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if ctx.Target().Os != ctx.Config().BuildOSCommonTarget.Os { + return + } + files := android.PathsForModuleSrc(ctx, r.props.Jars) androidAllDir := android.PathForModuleInstall(ctx, "android-all") @@ -390,6 +396,8 @@ func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleCont } } -func (r *robolectricRuntimes) InstallBypassMake() bool { return true } -func (r *robolectricRuntimes) InstallInTestcases() bool { return true } -func (r *robolectricRuntimes) InstallForceOS() *android.OsType { return &android.BuildOs } +func (r *robolectricRuntimes) InstallBypassMake() bool { return true } +func (r *robolectricRuntimes) InstallInTestcases() bool { return true } +func (r *robolectricRuntimes) InstallForceOS() (*android.OsType, *android.ArchType) { + return &android.BuildOs, &android.BuildArch +} diff --git a/java/sdk.go b/java/sdk.go index b44cd8e1a..56fa12b3e 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -191,6 +191,26 @@ func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool { return s.kind != sdkPrivate && s.kind != sdkNone && s.kind != sdkCorePlatform } +func (s sdkSpec) forVendorPartition(ctx android.EarlyModuleContext) sdkSpec { + // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value, + // use it instead of "current" for the vendor partition. + currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules() + if currentSdkVersion == "current" { + return s + } + + if s.kind == sdkPublic || s.kind == sdkSystem { + if s.version.isCurrent() { + if i, err := strconv.Atoi(currentSdkVersion); err == nil { + version := sdkVersion(i) + return sdkSpec{s.kind, version, s.raw} + } + panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion)) + } + } + return s +} + // usePrebuilt determines whether prebuilt SDK should be used for this sdkSpec with the given context. func (s sdkSpec) usePrebuilt(ctx android.EarlyModuleContext) bool { if s.version.isCurrent() { @@ -216,6 +236,10 @@ func (s sdkSpec) effectiveVersion(ctx android.EarlyModuleContext) (sdkVersion, e if !s.valid() { return s.version, fmt.Errorf("invalid sdk version %q", s.raw) } + + if ctx.DeviceSpecific() || ctx.SocSpecific() { + s = s.forVendorPartition(ctx) + } if s.version.isNumbered() { return s.version, nil } @@ -330,6 +354,10 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep return sdkDep{} } + if ctx.DeviceSpecific() || ctx.SocSpecific() { + sdkVersion = sdkVersion.forVendorPartition(ctx) + } + if !sdkVersion.validateSystemSdk(ctx) { return sdkDep{} } diff --git a/java/sdk_library.go b/java/sdk_library.go index 2aae42fc9..1a5ef544c 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -419,6 +419,9 @@ type sdkLibraryProperties struct { // $(location <label>): the path to the droiddoc_option_files with name <label> Droiddoc_options []string + // is set to true, Metalava will allow framework SDK to contain annotations. + Annotations_enabled *bool + // a list of top-level directories containing files to merge qualifier annotations // (i.e. those intended to be included in the stubs written) from. Merge_annotations_dirs []string @@ -572,9 +575,7 @@ func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep an type commonToSdkLibraryAndImportProperties struct { // The naming scheme to use for the components that this module creates. // - // If not specified then it defaults to "default". The other allowable value is - // "framework-modules" which matches the scheme currently used by framework modules - // for the equivalent components represented as separate Soong modules. + // If not specified then it defaults to "default". // // This is a temporary mechanism to simplify conversion from separate modules for each // component that follow a different naming pattern to the default one. @@ -618,8 +619,6 @@ func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android switch schemeProperty { case "default": c.namingScheme = &defaultNamingScheme{} - case "framework-modules": - c.namingScheme = &frameworkModulesNamingScheme{} default: ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty) return false @@ -849,22 +848,20 @@ func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *andr } // to satisfy SdkLibraryComponentDependency -func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string { - if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil { - return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack} - } - return nil +func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string { + return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack } // Implemented by modules that are (or possibly could be) a component of a java_sdk_library // (including the java_sdk_library) itself. type SdkLibraryComponentDependency interface { + UsesLibraryDependency + // The optional name of the sdk library that should be implicitly added to the // AndroidManifest of an app that contains code which references the sdk library. // - // Returns an array containing 0 or 1 items rather than a *string to make it easier - // to append this to the list of exported sdk libraries. - OptionalImplicitSdkLibrary() []string + // Returns the name of the optional implicit SDK library or nil, if there isn't one. + OptionalImplicitSdkLibrary() *string } // Make sure that all the module types that are components of java_sdk_library/_import @@ -1088,11 +1085,25 @@ func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) stri return ":" + module.BaseModuleName() + "-removed.api." + apiScope.name + ".latest" } +func childModuleVisibility(childVisibility []string) []string { + if childVisibility == nil { + // No child visibility set. The child will use the visibility of the sdk_library. + return nil + } + + // Prepend an override to ignore the sdk_library's visibility, and rely on the child visibility. + var visibility []string + visibility = append(visibility, "//visibility:override") + visibility = append(visibility, childVisibility...) + return visibility +} + // Creates the implementation java library func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) { - moduleNamePtr := proptools.StringPtr(module.BaseModuleName()) + visibility := childModuleVisibility(module.sdkLibraryProperties.Impl_library_visibility) + props := struct { Name *string Visibility []string @@ -1100,7 +1111,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) ConfigurationName *string }{ Name: proptools.StringPtr(module.implLibraryModuleName()), - Visibility: module.sdkLibraryProperties.Impl_library_visibility, + Visibility: visibility, // Set the instrument property to ensure it is instrumented when instrumentation is required. Instrument: true, @@ -1147,12 +1158,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext }{} props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope)) - - // If stubs_library_visibility is not set then the created module will use the - // visibility of this module. - visibility := module.sdkLibraryProperties.Stubs_library_visibility - props.Visibility = visibility - + props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_library_visibility) // sources are generated from the droiddoc props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)} sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) @@ -1161,6 +1167,11 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext props.Patch_module = module.properties.Patch_module props.Installable = proptools.BoolPtr(false) props.Libs = module.sdkLibraryProperties.Stub_only_libs + // The stub-annotations library contains special versions of the annotations + // with CLASS retention policy, so that they're kept. + if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) { + props.Libs = append(props.Libs, "stub-annotations") + } props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags // We compile the stubs for 1.8 in line with the main android.jar stubs, and potential @@ -1195,6 +1206,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC Arg_files []string Args *string Java_version *string + Annotations_enabled *bool Merge_annotations_dirs []string Merge_inclusion_annotations_dirs []string Generate_stubs *bool @@ -1227,12 +1239,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC // * libs (static_libs/libs) props.Name = proptools.StringPtr(name) - - // If stubs_source_visibility is not set then the created module will use the - // visibility of this module. - visibility := module.sdkLibraryProperties.Stubs_source_visibility - props.Visibility = visibility - + props.Visibility = childModuleVisibility(module.sdkLibraryProperties.Stubs_source_visibility) props.Srcs = append(props.Srcs, module.properties.Srcs...) props.Sdk_version = module.deviceProperties.Sdk_version props.System_modules = module.deviceProperties.System_modules @@ -1245,6 +1252,7 @@ func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookC props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs props.Java_version = module.properties.Java_version + props.Annotations_enabled = module.sdkLibraryProperties.Annotations_enabled props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs @@ -1376,22 +1384,22 @@ func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) and return android.Paths{jarPath.Path()} } -// Get the apex name for module, "" if it is for platform. -func getApexNameForModule(module android.Module) string { +// Get the apex names for module, nil if it is for platform. +func getApexNamesForModule(module android.Module) []string { if apex, ok := module.(android.ApexModule); ok { - return apex.ApexVariationName() + return apex.InApexes() } - return "" + return nil } -// Check to see if the other module is within the same named APEX as this module. +// Check to see if the other module is within the same set of named APEXes as this module. // // If either this or the other module are on the platform then this will return // false. -func withinSameApexAs(module android.ApexModule, other android.Module) bool { - name := module.ApexVariationName() - return name != "" && getApexNameForModule(other) == name +func withinSameApexesAs(module android.ApexModule, other android.Module) bool { + names := module.InApexes() + return len(names) > 0 && reflect.DeepEqual(names, getApexNamesForModule(other)) } func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { @@ -1410,7 +1418,7 @@ func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkS // Only allow access to the implementation library in the following condition: // * No sdk_version specified on the referencing module. // * The referencing module is in the same apex as this. - if sdkVersion.kind == sdkPrivate || withinSameApexAs(module, ctx.Module()) { + if sdkVersion.kind == sdkPrivate || withinSameApexesAs(module, ctx.Module()) { if headerJars { return module.HeaderJars() } else { @@ -1576,31 +1584,6 @@ func (s *defaultNamingScheme) apiModuleName(scope *apiScope, baseName string) st var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil) -type frameworkModulesNamingScheme struct { -} - -func (s *frameworkModulesNamingScheme) moduleSuffix(scope *apiScope) string { - suffix := scope.name - if scope == apiScopeModuleLib { - suffix = "module_libs_" - } - return suffix -} - -func (s *frameworkModulesNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string { - return fmt.Sprintf("%s-stubs-%sapi", baseName, s.moduleSuffix(scope)) -} - -func (s *frameworkModulesNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string { - return fmt.Sprintf("%s-stubs-srcs-%sapi", baseName, s.moduleSuffix(scope)) -} - -func (s *frameworkModulesNamingScheme) apiModuleName(scope *apiScope, baseName string) string { - return fmt.Sprintf("%s-api-%sapi", baseName, s.moduleSuffix(scope)) -} - -var _ sdkLibraryComponentNamingScheme = (*frameworkModulesNamingScheme)(nil) - func moduleStubLinkType(name string) (stub bool, ret linkType) { // This suffix-based approach is fragile and could potentially mis-trigger. // TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly. @@ -1949,7 +1932,7 @@ func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersio // For consistency with SdkLibrary make the implementation jar available to libraries that // are within the same APEX. implLibraryModule := module.implLibraryModule - if implLibraryModule != nil && withinSameApexAs(module, ctx.Module()) { + if implLibraryModule != nil && withinSameApexesAs(module, ctx.Module()) { if headerJars { return implLibraryModule.HeaderJars() } else { @@ -1972,7 +1955,7 @@ func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleCont return module.sdkJars(ctx, sdkVersion, false) } -// to satisfy apex.javaDependency interface +// to satisfy SdkLibraryDependency interface func (module *SdkLibraryImport) DexJarBuildPath() android.Path { if module.implLibraryModule == nil { return nil @@ -1981,6 +1964,15 @@ func (module *SdkLibraryImport) DexJarBuildPath() android.Path { } } +// to satisfy SdkLibraryDependency interface +func (module *SdkLibraryImport) DexJarInstallPath() android.Path { + if module.implLibraryModule == nil { + return nil + } else { + return module.implLibraryModule.DexJarInstallPath() + } +} + // to satisfy apex.javaDependency interface func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { if module.implLibraryModule == nil { @@ -2056,6 +2048,17 @@ func sdkLibraryXmlFactory() android.Module { return module } +func (module *sdkLibraryXml) UniqueApexVariations() bool { + // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the + // mounted APEX, which contains the name of the APEX. + return true +} + +// from android.PrebuiltEtcModule +func (module *sdkLibraryXml) BaseDir() string { + return "etc" +} + // from android.PrebuiltEtcModule func (module *sdkLibraryXml) SubDir() string { return "permissions" diff --git a/java/testing.go b/java/testing.go index 1e725fa73..322dc9ec6 100644 --- a/java/testing.go +++ b/java/testing.go @@ -44,6 +44,9 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string "prebuilts/sdk/17/public/android.jar": nil, "prebuilts/sdk/17/public/framework.aidl": nil, "prebuilts/sdk/17/system/android.jar": nil, + "prebuilts/sdk/28/public/android.jar": nil, + "prebuilts/sdk/28/public/framework.aidl": nil, + "prebuilts/sdk/28/system/android.jar": nil, "prebuilts/sdk/29/public/android.jar": nil, "prebuilts/sdk/29/public/framework.aidl": nil, "prebuilts/sdk/29/system/android.jar": nil, @@ -92,11 +95,10 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string MAIN_FILE = '%main%'`), // For java_sdk_library - "api/module-lib-current.txt": nil, - "api/module-lib-removed.txt": nil, - "api/system-server-current.txt": nil, - "api/system-server-removed.txt": nil, - "build/soong/scripts/gen-java-current-api-files.sh": nil, + "api/module-lib-current.txt": nil, + "api/module-lib-removed.txt": nil, + "api/system-server-current.txt": nil, + "api/system-server-removed.txt": nil, } cc.GatherRequiredFilesForTest(mockFS) @@ -143,6 +145,7 @@ func GatherRequiredDepsForTest() string { srcs: ["a.java"], sdk_version: "none", system_modules: "stable-core-platform-api-stubs-system-modules", + compile_dex: true, } `, extra) } diff --git a/rust/Android.bp b/rust/Android.bp index bbeb28d0b..8618207a1 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -19,7 +19,9 @@ bootstrap_go_package { "prebuilt.go", "proc_macro.go", "project_json.go", + "protobuf.go", "rust.go", + "strip.go", "source_provider.go", "test.go", "testing.go", @@ -33,6 +35,7 @@ bootstrap_go_package { "coverage_test.go", "library_test.go", "project_json_test.go", + "protobuf_test.go", "rust_test.go", "source_provider_test.go", "test_test.go", diff --git a/rust/androidmk.go b/rust/androidmk.go index fda0a2579..edae0e63d 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -96,7 +96,6 @@ func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.Andr ret.Class = "EXECUTABLES" ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { - fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String()) if binary.coverageOutputZipFile.Valid() { fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+binary.coverageOutputZipFile.String()) } @@ -139,9 +138,6 @@ func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.An } ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { - if !library.rlib() { - fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String()) - } if library.coverageOutputZipFile.Valid() { fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+library.coverageOutputZipFile.String()) } @@ -169,23 +165,32 @@ func (sourceProvider *BaseSourceProvider) AndroidMk(ctx AndroidMkContext, ret *a stem, suffix, _ := android.SplitFileExt(file) fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix) fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem) + fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") }) } func (bindgen *bindgenDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { ctx.SubAndroidMk(ret, bindgen.BaseSourceProvider) - ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { - fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") - }) +} + +func (proto *protobufDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ctx.SubAndroidMk(ret, proto.BaseSourceProvider) } func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + var unstrippedOutputFile android.OptionalPath // Soong installation is only supported for host modules. Have Make // installation trigger Soong installation. if ctx.Target().Os.Class == android.Host { ret.OutputFile = android.OptionalPathForPath(compiler.path) + } else if compiler.strippedOutputFile.Valid() { + unstrippedOutputFile = ret.OutputFile + ret.OutputFile = compiler.strippedOutputFile } ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { + if compiler.strippedOutputFile.Valid() { + fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", unstrippedOutputFile) + } path, file := filepath.Split(compiler.path.ToMakePath().String()) stem, suffix, _ := android.SplitFileExt(file) fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix) diff --git a/rust/binary.go b/rust/binary.go index 1a82c9208..1d02453db 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -24,13 +24,11 @@ func init() { } type BinaryCompilerProperties struct { - // passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib - // (assuming it has no dylib dependencies already) - Prefer_dynamic *bool } type binaryDecorator struct { *baseCompiler + stripper Stripper Properties BinaryCompilerProperties } @@ -60,10 +58,6 @@ func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator return module, binary } -func (binary *binaryDecorator) preferDynamic() bool { - return Bool(binary.Properties.Prefer_dynamic) -} - func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = binary.baseCompiler.compilerFlags(ctx, flags) @@ -76,9 +70,6 @@ func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Fla "-Wl,--no-undefined-version") } - if binary.preferDynamic() { - flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic") - } return flags } @@ -96,7 +87,8 @@ func (binary *binaryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { func (binary *binaryDecorator) compilerProps() []interface{} { return append(binary.baseCompiler.compilerProps(), - &binary.Properties) + &binary.Properties, + &binary.stripper.StripProperties) } func (binary *binaryDecorator) nativeCoverage() bool { @@ -105,15 +97,20 @@ func (binary *binaryDecorator) nativeCoverage() bool { func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix() - srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs) - outputFile := android.PathForModuleOut(ctx, fileName) - binary.unstrippedOutputFile = outputFile flags.RustFlags = append(flags.RustFlags, deps.depFlags...) + flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) outputs := TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) + + if binary.stripper.NeedsStrip(ctx) { + strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName) + binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile) + binary.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile) + } + binary.coverageFile = outputs.coverageFile var coverageFiles android.Paths @@ -132,8 +129,9 @@ func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath { return binary.coverageOutputZipFile } -func (binary *binaryDecorator) autoDep() autoDep { - if binary.preferDynamic() { +func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep { + // Binaries default to dylib dependencies for device, rlib for host. + if ctx.Device() { return dylibAutoDep } else { return rlibAutoDep diff --git a/rust/binary_test.go b/rust/binary_test.go index b9c8698b9..cfef57a77 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -17,44 +17,112 @@ package rust import ( "strings" "testing" + + "android/soong/android" ) -// Test that the prefer_dynamic property is handled correctly. -func TestPreferDynamicBinary(t *testing.T) { +// Test that rustlibs default linkage is correct for binaries. +func TestBinaryLinkage(t *testing.T) { ctx := testRust(t, ` - rust_binary_host { - name: "fizz-buzz-dynamic", + rust_binary { + name: "fizz-buzz", srcs: ["foo.rs"], - prefer_dynamic: true, + rustlibs: ["libfoo"], + host_supported: true, } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + host_supported: true, + }`) + + fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) + fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module) + + if !android.InList("libfoo", fizzBuzzHost.Properties.AndroidMkRlibs) { + t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules") + } + + if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) { + t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules") + } +} +// Test that the path returned by HostToolPath is correct +func TestHostToolPath(t *testing.T) { + ctx := testRust(t, ` rust_binary_host { name: "fizz-buzz", srcs: ["foo.rs"], }`) - fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz") - fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic") - path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath() if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) { t.Errorf("wrong host tool path, expected %q got %q", w, g) } +} + +// Test that the flags being passed to rust_binary modules are as expected +func TestBinaryFlags(t *testing.T) { + ctx := testRust(t, ` + rust_binary_host { + name: "fizz-buzz", + srcs: ["foo.rs"], + }`) - // Do not compile binary modules with the --test flag. - flags := fizzBuzzDynamic.Args["rustcFlags"] + fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz") + + flags := fizzBuzz.Args["rustcFlags"] if strings.Contains(flags, "--test") { t.Errorf("extra --test flag, rustcFlags: %#v", flags) } - if !strings.Contains(flags, "prefer-dynamic") { - t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags) +} + +func TestLinkObjects(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "fizz-buzz", + srcs: ["foo.rs"], + shared_libs: ["libfoo"], + } + cc_library { + name: "libfoo", + }`) + + fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Output("fizz-buzz") + linkFlags := fizzBuzz.Args["linkFlags"] + if !strings.Contains(linkFlags, "/libfoo.so") { + t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags) } +} - flags = fizzBuzz.Args["rustcFlags"] - if strings.Contains(flags, "--test") { - t.Errorf("extra --test flag, rustcFlags: %#v", flags) +// Test that stripped versions are correctly generated and used. +func TestStrippedBinary(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "foo", + srcs: ["foo.rs"], + } + rust_binary { + name: "bar", + srcs: ["foo.rs"], + strip: { + none: true + } + } + `) + + foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a") + foo.Output("stripped/foo") + // Check that the `cp` rules is using the stripped version as input. + cp := foo.Rule("android.Cp") + if !strings.HasSuffix(cp.Input.String(), "stripped/foo") { + t.Errorf("installed binary not based on stripped version: %v", cp.Input) } - if strings.Contains(flags, "prefer-dynamic") { - t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags) + + fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("stripped/bar") + if fizzBar.Rule != nil { + t.Errorf("stripped version of bar has been generated") } } diff --git a/rust/bindgen.go b/rust/bindgen.go index 9b09e616e..cafdb8bfa 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -21,22 +21,20 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" - ccConfig "android/soong/cc/config" ) var ( defaultBindgenFlags = []string{""} // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures. - bindgenClangVersion = "clang-r383902c" - bindgenLibClangSoGit = "11git" + bindgenClangVersion = "clang-r383902c" //TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen. _ = pctx.SourcePathVariable("bindgenCmd", "out/host/${config.HostPrebuiltTag}/bin/bindgen") _ = pctx.SourcePathVariable("bindgenClang", - "${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang") + "${cc_config.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang") _ = pctx.SourcePathVariable("bindgenLibClang", - "${ccConfig.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/lib64/libclang.so."+bindgenLibClangSoGit) + "${cc_config.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/lib64/") //TODO(ivanlozano) Switch this to RuleBuilder bindgen = pctx.AndroidStaticRule("bindgen", @@ -92,24 +90,23 @@ type bindgenDecorator struct { Properties BindgenProperties } -func (b *bindgenDecorator) GenerateSource(ctx android.ModuleContext, deps PathDeps) android.Path { - ccToolchain := ccConfig.FindToolchain(ctx.Os(), ctx.Arch()) +func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path { + ccToolchain := ctx.RustModule().ccToolchain(ctx) var cflags []string var implicits android.Paths - implicits = append(implicits, deps.depIncludePaths...) - implicits = append(implicits, deps.depSystemIncludePaths...) + implicits = append(implicits, deps.depGeneratedHeaders...) // Default clang flags - cflags = append(cflags, "${ccConfig.CommonClangGlobalCflags}") + cflags = append(cflags, "${cc_config.CommonClangGlobalCflags}") if ctx.Device() { - cflags = append(cflags, "${ccConfig.DeviceClangGlobalCflags}") + cflags = append(cflags, "${cc_config.DeviceClangGlobalCflags}") } // Toolchain clang flags cflags = append(cflags, "-target "+ccToolchain.ClangTriple()) - cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${ccConfig.")) + cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${cc_config.")) // Dependency clang flags and include paths cflags = append(cflags, deps.depClangFlags...) diff --git a/rust/builder.go b/rust/builder.go index 45cd268e9..654b1e6bf 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -31,9 +31,14 @@ var ( Command: "$envVars $rustcCmd " + "-C linker=${config.RustLinker} " + "-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " + - "--emit link -o $out --emit dep-info=$out.d $in ${libFlags} $rustcFlags", + "--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" + + " && grep \"^$out:\" $out.d.raw > $out.d", CommandDeps: []string{"$rustcCmd"}, // Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633 + // Rustc emits unneeded dependency lines for the .d and input .rs files. + // Those extra lines cause ninja warning: + // "warning: depfile has multiple output paths" + // For ninja, we keep/grep only the dependency rule for the rust $out file. Deps: blueprint.DepsGCC, Depfile: "$out.d", }, diff --git a/rust/compiler.go b/rust/compiler.go index ef7fb8cfc..664578d82 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -129,8 +129,9 @@ type baseCompiler struct { location installLocation coverageOutputZipFile android.OptionalPath - unstrippedOutputFile android.Path distFile android.OptionalPath + // Stripped output file. If Valid(), this file will be installed instead of outputFile. + strippedOutputFile android.OptionalPath } func (compiler *baseCompiler) Disabled() bool { @@ -145,6 +146,10 @@ func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath { panic("baseCompiler does not implement coverageOutputZipPath()") } +func (compiler *baseCompiler) static() bool { + return false +} + var _ compiler = (*baseCompiler)(nil) func (compiler *baseCompiler) inData() bool { @@ -211,12 +216,20 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { if !Bool(compiler.Properties.No_stdlibs) { for _, stdlib := range config.Stdlibs { - // If we're building for the primary host target, use the compiler's stdlibs - if ctx.Host() && ctx.TargetPrimary() { + // If we're building for the primary arch of the build host, use the compiler's stdlibs + if ctx.Target().Os == android.BuildOs && ctx.TargetPrimary() { stdlib = stdlib + "_" + ctx.toolchain().RustTriple() } - deps.Rustlibs = append(deps.Rustlibs, stdlib) + // For devices, we always link stdlibs in as dylibs except for ffi static libraries. + // (rustc does not support linking libstd as a dylib for ffi static libraries) + if ctx.Host() { + deps.Rustlibs = append(deps.Rustlibs, stdlib) + } else if ctx.RustModule().compiler.static() { + deps.Rlibs = append(deps.Rlibs, stdlib) + } else { + deps.Dylibs = append(deps.Dylibs, stdlib) + } } } return deps @@ -257,8 +270,12 @@ func (compiler *baseCompiler) nativeCoverage() bool { return false } -func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) { - compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file) +func (compiler *baseCompiler) install(ctx ModuleContext) { + path := ctx.RustModule().outputFile + if compiler.strippedOutputFile.Valid() { + path = compiler.strippedOutputFile + } + compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path()) } func (compiler *baseCompiler) getStem(ctx ModuleContext) string { diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 8b9fccc61..56a8ef8ac 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -177,3 +177,30 @@ func TestLints(t *testing.T) { }) } } + +// Test that devices are linking the stdlib dynamically +func TestStdDeviceLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_binary { + name: "fizz", + srcs: ["foo.rs"], + } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + }`) + fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) + fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module) + fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) + + if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for device binaries") + } + if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for rlibs") + } + if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) { + t.Errorf("libstd is not linked dynamically for dylibs") + } +} diff --git a/rust/config/Android.bp b/rust/config/Android.bp index bcfac7c06..e0cc4ce07 100644 --- a/rust/config/Android.bp +++ b/rust/config/Android.bp @@ -16,5 +16,6 @@ bootstrap_go_package { "x86_linux_host.go", "x86_device.go", "x86_64_device.go", + "arm64_linux_host.go", ], } diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go index ed9f90bb9..62d469e4f 100644 --- a/rust/config/allowed_list.go +++ b/rust/config/allowed_list.go @@ -10,6 +10,7 @@ var ( "prebuilts/rust", "system/extras/profcollectd", "system/security", + "system/tools/aidl", } RustModuleTypes = []string{ diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go index 180fd8ba0..7d13c42aa 100644 --- a/rust/config/arm64_device.go +++ b/rust/config/arm64_device.go @@ -23,12 +23,7 @@ import ( var ( Arm64RustFlags = []string{} Arm64ArchFeatureRustFlags = map[string][]string{} - Arm64LinkFlags = []string{ - "-Wl,--icf=safe", - "-Wl,-z,max-page-size=4096", - - "-Wl,-z,separate-code", - } + Arm64LinkFlags = []string{} Arm64ArchVariantRustFlags = map[string][]string{ "armv8-a": []string{}, @@ -59,7 +54,8 @@ func (t *toolchainArm64) RustTriple() string { } func (t *toolchainArm64) ToolchainLinkFlags() string { - return "${config.DeviceGlobalLinkFlags} ${config.Arm64ToolchainLinkFlags}" + // Prepend the lld flags from cc_config so we stay in sync with cc + return "${config.DeviceGlobalLinkFlags} ${cc_config.Arm64Lldflags} ${config.Arm64ToolchainLinkFlags}" } func (t *toolchainArm64) ToolchainRustFlags() string { @@ -75,9 +71,16 @@ func (t *toolchainArm64) Supported() bool { } func Arm64ToolchainFactory(arch android.Arch) Toolchain { + archVariant := arch.ArchVariant + if archVariant == "" { + // arch variants defaults to armv8-a. This is mostly for + // the host target which borrows toolchain configs from here. + archVariant = "armv8-a" + } + toolchainRustFlags := []string{ "${config.Arm64ToolchainRustFlags}", - "${config.Arm64" + arch.ArchVariant + "VariantRustFlags}", + "${config.Arm64" + archVariant + "VariantRustFlags}", } toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...) diff --git a/rust/config/arm64_linux_host.go b/rust/config/arm64_linux_host.go new file mode 100644 index 000000000..baf9cf836 --- /dev/null +++ b/rust/config/arm64_linux_host.go @@ -0,0 +1,24 @@ +// Copyright 2019 The Android Open Source Project +// +// 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 config + +import ( + "android/soong/android" +) + +func init() { + // Linux_cross-arm64 uses the same rust toolchain as the Android-arm64 + registerToolchainFactory(android.LinuxBionic, android.Arm64, Arm64ToolchainFactory) +} diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go index ac2580b81..ac4f1c659 100644 --- a/rust/config/arm_device.go +++ b/rust/config/arm_device.go @@ -23,10 +23,7 @@ import ( var ( ArmRustFlags = []string{} ArmArchFeatureRustFlags = map[string][]string{} - ArmLinkFlags = []string{ - "-Wl,--icf=safe", - "-Wl,-m,armelf", - } + ArmLinkFlags = []string{} ArmArchVariantRustFlags = map[string][]string{ "armv7-a": []string{}, @@ -59,7 +56,8 @@ func (t *toolchainArm) RustTriple() string { } func (t *toolchainArm) ToolchainLinkFlags() string { - return "${config.DeviceGlobalLinkFlags} ${config.ArmToolchainLinkFlags}" + // Prepend the lld flags from cc_config so we stay in sync with cc + return "${config.DeviceGlobalLinkFlags} ${cc_config.ArmLldflags} ${config.ArmToolchainLinkFlags}" } func (t *toolchainArm) ToolchainRustFlags() string { diff --git a/rust/config/global.go b/rust/config/global.go index 2020f461d..6a5251bb5 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -24,7 +24,7 @@ import ( var pctx = android.NewPackageContext("android/soong/rust/config") var ( - RustDefaultVersion = "1.44.0" + RustDefaultVersion = "1.45.2" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2018" Stdlibs = []string{ @@ -42,21 +42,18 @@ var ( deviceGlobalRustFlags = []string{} deviceGlobalLinkFlags = []string{ + // Prepend the lld flags from cc_config so we stay in sync with cc + "${cc_config.DeviceGlobalLldflags}", + + // Override cc's --no-undefined-version to allow rustc's generated alloc functions + "-Wl,--undefined-version", + "-Bdynamic", "-nostdlib", - "-Wl,-z,noexecstack", - "-Wl,-z,relro", - "-Wl,-z,now", - "-Wl,--build-id=md5", - "-Wl,--warn-shared-textrel", - "-Wl,--fatal-warnings", - "-Wl,--pack-dyn-relocs=android+relr", + "-Wl,--use-android-relr-tags", "-Wl,--no-undefined", - "-Wl,--hash-style=gnu", - - "-B${ccConfig.ClangBin}", - "-fuse-ld=lld", + "-B${cc_config.ClangBin}", } ) @@ -81,8 +78,8 @@ func init() { pctx.StaticVariable("RustPath", "${RustBase}/${HostPrebuiltTag}/${RustVersion}") pctx.StaticVariable("RustBin", "${RustPath}/bin") - pctx.ImportAs("ccConfig", "android/soong/cc/config") - pctx.StaticVariable("RustLinker", "${ccConfig.ClangBin}/clang++") + pctx.ImportAs("cc_config", "android/soong/cc/config") + pctx.StaticVariable("RustLinker", "${cc_config.ClangBin}/clang++") pctx.StaticVariable("RustLinkerArgs", "") pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " ")) diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go index 9a6c00b19..5f6e85a08 100644 --- a/rust/config/x86_64_device.go +++ b/rust/config/x86_64_device.go @@ -61,7 +61,8 @@ func (t *toolchainX86_64) RustTriple() string { } func (t *toolchainX86_64) ToolchainLinkFlags() string { - return "${config.DeviceGlobalLinkFlags} ${config.X86_64ToolchainLinkFlags}" + // Prepend the lld flags from cc_config so we stay in sync with cc + return "${config.DeviceGlobalLinkFlags} ${cc_config.X86_64Lldflags} ${config.X86_64ToolchainLinkFlags}" } func (t *toolchainX86_64) ToolchainRustFlags() string { diff --git a/rust/config/x86_darwin_host.go b/rust/config/x86_darwin_host.go index 4104400c1..ddd93e889 100644 --- a/rust/config/x86_darwin_host.go +++ b/rust/config/x86_darwin_host.go @@ -23,7 +23,7 @@ import ( var ( DarwinRustFlags = []string{} DarwinRustLinkFlags = []string{ - "-B${ccConfig.MacToolPath}", + "-B${cc_config.MacToolPath}", } darwinX8664Rustflags = []string{} darwinX8664Linkflags = []string{} @@ -77,7 +77,8 @@ func (t *toolchainDarwin) ProcMacroSuffix() string { } func (t *toolchainDarwinX8664) ToolchainLinkFlags() string { - return "${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainX8664LinkFlags}" + // Prepend the lld flags from cc_config so we stay in sync with cc + return "${cc_config.DarwinClangLldflags} ${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainX8664LinkFlags}" } func (t *toolchainDarwinX8664) ToolchainRustFlags() string { diff --git a/rust/config/x86_device.go b/rust/config/x86_device.go index ec19b3c30..daeeb1476 100644 --- a/rust/config/x86_device.go +++ b/rust/config/x86_device.go @@ -64,7 +64,8 @@ func (t *toolchainX86) RustTriple() string { } func (t *toolchainX86) ToolchainLinkFlags() string { - return "${config.DeviceGlobalLinkFlags} ${config.X86ToolchainLinkFlags}" + // Prepend the lld flags from cc_config so we stay in sync with cc + return "${config.DeviceGlobalLinkFlags} ${cc_config.X86ClangLldflags} ${config.X86ToolchainLinkFlags}" } func (t *toolchainX86) ToolchainRustFlags() string { diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go index acc99e1c2..e7f26ce5c 100644 --- a/rust/config/x86_linux_host.go +++ b/rust/config/x86_linux_host.go @@ -23,8 +23,9 @@ import ( var ( LinuxRustFlags = []string{} LinuxRustLinkFlags = []string{ - "-B${ccConfig.ClangBin}", + "-B${cc_config.ClangBin}", "-fuse-ld=lld", + "-Wl,--undefined-version", } linuxX86Rustflags = []string{} linuxX86Linkflags = []string{} @@ -77,7 +78,9 @@ func (t *toolchainLinuxX8664) RustTriple() string { } func (t *toolchainLinuxX8664) ToolchainLinkFlags() string { - return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}" + // Prepend the lld flags from cc_config so we stay in sync with cc + return "${cc_config.LinuxClangLldflags} ${cc_config.LinuxX8664ClangLldflags} " + + "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}" } func (t *toolchainLinuxX8664) ToolchainRustFlags() string { @@ -105,7 +108,9 @@ func (t *toolchainLinuxX86) RustTriple() string { } func (t *toolchainLinuxX86) ToolchainLinkFlags() string { - return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}" + // Prepend the lld flags from cc_config so we stay in sync with cc + return "${cc_config.LinuxClangLldflags} ${cc_config.LinuxX86ClangLldflags} " + + "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}" } func (t *toolchainLinuxX86) ToolchainRustFlags() string { diff --git a/rust/coverage.go b/rust/coverage.go index 223ba4f19..26375f507 100644 --- a/rust/coverage.go +++ b/rust/coverage.go @@ -53,7 +53,7 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags flags.Coverage = true coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface) flags.RustFlags = append(flags.RustFlags, - "-Z profile", "-g", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads") + "-Z profile", "-g", "-C opt-level=0", "-C link-dead-code") flags.LinkFlags = append(flags.LinkFlags, "--coverage", "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,getenv") deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path()) diff --git a/rust/coverage_test.go b/rust/coverage_test.go index 357c2e8b1..73673d035 100644 --- a/rust/coverage_test.go +++ b/rust/coverage_test.go @@ -56,7 +56,7 @@ func TestCoverageFlags(t *testing.T) { fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc") buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc") - rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads"} + rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code"} for _, flag := range rustcCoverageFlags { missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v" containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v" diff --git a/rust/library.go b/rust/library.go index 6766d618b..a44293307 100644 --- a/rust/library.go +++ b/rust/library.go @@ -78,6 +78,7 @@ type LibraryMutatedProperties struct { type libraryDecorator struct { *baseCompiler *flagExporter + stripper Stripper Properties LibraryCompilerProperties MutatedProperties LibraryMutatedProperties @@ -176,13 +177,13 @@ func (library *libraryDecorator) setStatic() { library.MutatedProperties.VariantIsDylib = false } -func (library *libraryDecorator) autoDep() autoDep { +func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep { if library.rlib() || library.static() { return rlibAutoDep } else if library.dylib() || library.shared() { return dylibAutoDep } else { - return rlibAutoDep + panic("autoDep called on library" + ctx.ModuleName() + "that has no enabled variants.") } } @@ -338,7 +339,8 @@ func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorat func (library *libraryDecorator) compilerProps() []interface{} { return append(library.baseCompiler.compilerProps(), &library.Properties, - &library.MutatedProperties) + &library.MutatedProperties, + &library.stripper.StripProperties) } func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { @@ -371,7 +373,8 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) F } func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path { - var outputFile android.WritablePath + var outputFile android.ModuleOutPath + var fileName string var srcPath android.Path if library.sourceProvider != nil { @@ -381,6 +384,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } flags.RustFlags = append(flags.RustFlags, deps.depFlags...) + flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) if library.dylib() { // We need prefer-dynamic for now to avoid linking in the static stdlib. See: @@ -390,31 +394,37 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } if library.rlib() { - fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix() + fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix() outputFile = android.PathForModuleOut(ctx, fileName) outputs := TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) library.coverageFile = outputs.coverageFile } else if library.dylib() { - fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix() + fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix() outputFile = android.PathForModuleOut(ctx, fileName) outputs := TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) library.coverageFile = outputs.coverageFile } else if library.static() { - fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix() + fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix() outputFile = android.PathForModuleOut(ctx, fileName) outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) library.coverageFile = outputs.coverageFile } else if library.shared() { - fileName := library.sharedLibFilename(ctx) + fileName = library.sharedLibFilename(ctx) outputFile = android.PathForModuleOut(ctx, fileName) outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) library.coverageFile = outputs.coverageFile } + if !library.rlib() && library.stripper.NeedsStrip(ctx) { + strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName) + library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile) + library.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile) + } + var coverageFiles android.Paths if library.coverageFile != nil { coverageFiles = append(coverageFiles, library.coverageFile) @@ -427,8 +437,8 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa if library.rlib() || library.dylib() { library.exportLinkDirs(deps.linkDirs...) library.exportDepFlags(deps.depFlags...) + library.exportLinkObjects(deps.linkObjects...) } - library.unstrippedOutputFile = outputFile return outputFile } diff --git a/rust/library_test.go b/rust/library_test.go index 8a91cf10f..f1bc0507b 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -144,6 +144,22 @@ func TestSharedLibrary(t *testing.T) { } } +func TestStaticLibraryLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_ffi_static { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + }`) + + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static") + + if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) { + t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v", + libfoo.Module().(*Module).Properties.AndroidMkDylibs) + } +} + // Test that variants pull in the right type of rustlib autodep func TestAutoDeps(t *testing.T) { @@ -190,3 +206,35 @@ func TestAutoDeps(t *testing.T) { } } + +// Test that stripped versions are correctly generated and used. +func TestStrippedLibrary(t *testing.T) { + ctx := testRust(t, ` + rust_library_dylib { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.rs"], + } + rust_library_dylib { + name: "libbar", + crate_name: "bar", + srcs: ["foo.rs"], + strip: { + none: true + } + } + `) + + foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib") + foo.Output("stripped/libfoo.dylib.so") + // Check that the `cp` rule is using the stripped version as input. + cp := foo.Rule("android.Cp") + if !strings.HasSuffix(cp.Input.String(), "stripped/libfoo.dylib.so") { + t.Errorf("installed binary not based on stripped version: %v", cp.Input) + } + + fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("stripped/libbar.dylib.so") + if fizzBar.Rule != nil { + t.Errorf("stripped version of bar has been generated") + } +} diff --git a/rust/prebuilt.go b/rust/prebuilt.go index 3d081c113..f9c8934d6 100644 --- a/rust/prebuilt.go +++ b/rust/prebuilt.go @@ -99,9 +99,6 @@ func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags if len(paths) > 0 { ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)") } - - prebuilt.unstrippedOutputFile = srcPath - return srcPath } diff --git a/rust/proc_macro.go b/rust/proc_macro.go index 3dd2521a3..0c6ec9953 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -66,9 +66,6 @@ func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, dep outputFile := android.PathForModuleOut(ctx, fileName) srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs) - - procMacro.unstrippedOutputFile = outputFile - TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile, deps.linkDirs) return outputFile } @@ -80,6 +77,6 @@ func (procMacro *procMacroDecorator) getStem(ctx ModuleContext) string { return stem + String(procMacro.baseCompiler.Properties.Suffix) } -func (procMacro *procMacroDecorator) autoDep() autoDep { +func (procMacro *procMacroDecorator) autoDep(ctx BaseModuleContext) autoDep { return rlibAutoDep } diff --git a/rust/protobuf.go b/rust/protobuf.go new file mode 100644 index 000000000..897300f19 --- /dev/null +++ b/rust/protobuf.go @@ -0,0 +1,109 @@ +// Copyright 2020 The Android Open Source Project +// +// 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 rust + +import ( + "android/soong/android" +) + +var ( + defaultProtobufFlags = []string{""} +) + +func init() { + android.RegisterModuleType("rust_protobuf", RustProtobufFactory) + android.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory) +} + +var _ SourceProvider = (*protobufDecorator)(nil) + +type ProtobufProperties struct { + // Path to the proto file that will be used to generate the source + Proto *string `android:"path,arch_variant"` + + // List of additional flags to pass to aprotoc + Proto_flags []string `android:"arch_variant"` +} + +type protobufDecorator struct { + *BaseSourceProvider + + Properties ProtobufProperties +} + +func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path { + var protoFlags android.ProtoFlags + pluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust") + + protoFlags.OutTypeFlag = "--rust_out" + + protoFlags.Flags = append(protoFlags.Flags, " --plugin="+pluginPath.String()) + protoFlags.Flags = append(protoFlags.Flags, defaultProtobufFlags...) + protoFlags.Flags = append(protoFlags.Flags, proto.Properties.Proto_flags...) + + protoFlags.Deps = append(protoFlags.Deps, pluginPath) + + protoFile := android.OptionalPathForModuleSrc(ctx, proto.Properties.Proto) + if !protoFile.Valid() { + ctx.PropertyErrorf("proto", "invalid path to proto file") + } + + outDir := android.PathForModuleOut(ctx) + depFile := android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".d") + outputs := android.WritablePaths{android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".rs")} + + rule := android.NewRuleBuilder() + android.ProtoRule(ctx, rule, protoFile.Path(), protoFlags, protoFlags.Deps, outDir, depFile, outputs) + rule.Build(pctx, ctx, "protoc_"+protoFile.Path().Rel(), "protoc "+protoFile.Path().Rel()) + + proto.BaseSourceProvider.OutputFile = outputs[0] + return outputs[0] +} + +func (proto *protobufDecorator) SourceProviderProps() []interface{} { + return append(proto.BaseSourceProvider.SourceProviderProps(), &proto.Properties) +} + +func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps { + deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps) + deps.Rustlibs = append(deps.Rustlibs, "libprotobuf") + return deps +} + +// rust_protobuf generates protobuf rust code from the provided proto file. This uses the protoc-gen-rust plugin for +// protoc. Additional flags to the protoc command can be passed via the proto_flags property. This module type will +// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs +// properties of other modules. +func RustProtobufFactory() android.Module { + module, _ := NewRustProtobuf(android.HostAndDeviceSupported) + return module.Init() +} + +// A host-only variant of rust_protobuf. Refer to rust_protobuf for more details. +func RustProtobufHostFactory() android.Module { + module, _ := NewRustProtobuf(android.HostSupported) + return module.Init() +} + +func NewRustProtobuf(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) { + protobuf := &protobufDecorator{ + BaseSourceProvider: NewSourceProvider(), + Properties: ProtobufProperties{}, + } + + module := NewSourceProviderModule(hod, protobuf, false) + + return module, protobuf +} diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go new file mode 100644 index 000000000..a9dbf397d --- /dev/null +++ b/rust/protobuf_test.go @@ -0,0 +1,39 @@ +// Copyright 2020 The Android Open Source Project +// +// 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 rust + +import ( + "android/soong/android" + "testing" +) + +func TestRustProtobuf(t *testing.T) { + ctx := testRust(t, ` + rust_protobuf { + name: "librust_proto", + proto: "buf.proto", + crate_name: "rust_proto", + source_stem: "buf", + } + `) + // Check that there's a rule to generate the expected output + _ = ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Output("buf.rs") + + // Check that libprotobuf is added as a dependency. + librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module) + if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) { + t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)") + } +} diff --git a/rust/rust.go b/rust/rust.go index b69786976..b98992c9b 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -23,6 +23,7 @@ import ( "android/soong/android" "android/soong/cc" + cc_config "android/soong/cc/config" "android/soong/rust/config" ) @@ -42,7 +43,7 @@ func init() { ctx.BottomUp("rust_begin", BeginMutator).Parallel() }) pctx.Import("android/soong/rust/config") - pctx.ImportAs("ccConfig", "android/soong/cc/config") + pctx.ImportAs("cc_config", "android/soong/cc/config") } type Flags struct { @@ -244,18 +245,20 @@ type Deps struct { } type PathDeps struct { - DyLibs RustLibraries - RLibs RustLibraries - SharedLibs android.Paths - StaticLibs android.Paths - ProcMacros RustLibraries - linkDirs []string - depFlags []string + DyLibs RustLibraries + RLibs RustLibraries + SharedLibs android.Paths + StaticLibs android.Paths + ProcMacros RustLibraries + linkDirs []string + depFlags []string + linkObjects []string //ReexportedDeps android.Paths // Used by bindgen modules which call clang depClangFlags []string depIncludePaths android.Paths + depGeneratedHeaders android.Paths depSystemIncludePaths android.Paths coverageFiles android.Paths @@ -282,25 +285,30 @@ type compiler interface { crateName() string inData() bool - install(ctx ModuleContext, path android.Path) + install(ctx ModuleContext) relativeInstallPath() string nativeCoverage() bool Disabled() bool SetDisabled() + + static() bool } type exportedFlagsProducer interface { exportedLinkDirs() []string exportedDepFlags() []string + exportedLinkObjects() []string exportLinkDirs(...string) exportDepFlags(...string) + exportLinkObjects(...string) } type flagExporter struct { - depFlags []string - linkDirs []string + depFlags []string + linkDirs []string + linkObjects []string } func (flagExporter *flagExporter) exportedLinkDirs() []string { @@ -311,6 +319,10 @@ func (flagExporter *flagExporter) exportedDepFlags() []string { return flagExporter.depFlags } +func (flagExporter *flagExporter) exportedLinkObjects() []string { + return flagExporter.linkObjects +} + func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) { flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...)) } @@ -319,12 +331,17 @@ func (flagExporter *flagExporter) exportDepFlags(flags ...string) { flagExporter.depFlags = android.FirstUniqueStrings(append(flagExporter.depFlags, flags...)) } +func (flagExporter *flagExporter) exportLinkObjects(flags ...string) { + flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...)) +} + var _ exportedFlagsProducer = (*flagExporter)(nil) func NewFlagExporter() *flagExporter { return &flagExporter{ - depFlags: []string{}, - linkDirs: []string{}, + depFlags: []string{}, + linkDirs: []string{}, + linkObjects: []string{}, } } @@ -543,21 +560,6 @@ func (mod *Module) Init() android.Module { android.InitAndroidArchModule(mod, mod.hod, mod.multilib) android.InitDefaultableModule(mod) - - // Explicitly disable unsupported targets. - android.AddLoadHook(mod, func(ctx android.LoadHookContext) { - disableTargets := struct { - Target struct { - Linux_bionic struct { - Enabled *bool - } - } - }{} - disableTargets.Target.Linux_bionic.Enabled = proptools.BoolPtr(false) - - ctx.AppendProperties(&disableTargets) - }) - return mod } @@ -641,6 +643,10 @@ func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain { return mod.cachedToolchain } +func (mod *Module) ccToolchain(ctx android.BaseModuleContext) cc_config.Toolchain { + return cc_config.FindToolchain(ctx.Os(), ctx.Arch()) +} + func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { } @@ -684,7 +690,7 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { mod.outputFile = android.OptionalPathForPath(outputFile) if mod.outputFile.Valid() && !mod.Properties.PreventInstall { - mod.compiler.install(ctx, mod.outputFile.Path()) + mod.compiler.install(ctx) } } } @@ -740,7 +746,7 @@ var ( ) type autoDeppable interface { - autoDep() autoDep + autoDep(ctx BaseModuleContext) autoDep } func (mod *Module) begin(ctx BaseModuleContext) { @@ -811,6 +817,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if lib, ok := rustDep.compiler.(exportedFlagsProducer); ok && depTag != procMacroDepTag { depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedLinkDirs()...) depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...) + depPaths.linkObjects = append(depPaths.linkObjects, lib.exportedLinkObjects()...) } if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag { @@ -838,51 +845,49 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } } - linkFile := ccDep.OutputFile() - linkPath := linkPathFromFilePath(linkFile.Path()) - libName := libNameFromFilePath(linkFile.Path()) - depFlag := "-l" + libName + linkObject := ccDep.OutputFile() + linkPath := linkPathFromFilePath(linkObject.Path()) - if !linkFile.Valid() { + if !linkObject.Valid() { ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) } exportDep := false switch { case cc.IsStaticDepTag(depTag): - depFlag = "-lstatic=" + libName depPaths.linkDirs = append(depPaths.linkDirs, linkPath) - depPaths.depFlags = append(depPaths.depFlags, depFlag) + depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...) if mod, ok := ccDep.(*cc.Module); ok { depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...) depPaths.depClangFlags = append(depPaths.depClangFlags, mod.ExportedFlags()...) + depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, mod.ExportedGeneratedHeaders()...) } depPaths.coverageFiles = append(depPaths.coverageFiles, ccDep.CoverageFiles()...) directStaticLibDeps = append(directStaticLibDeps, ccDep) mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName) case cc.IsSharedDepTag(depTag): - depFlag = "-ldylib=" + libName depPaths.linkDirs = append(depPaths.linkDirs, linkPath) - depPaths.depFlags = append(depPaths.depFlags, depFlag) + depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...) if mod, ok := ccDep.(*cc.Module); ok { depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...) depPaths.depClangFlags = append(depPaths.depClangFlags, mod.ExportedFlags()...) + depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, mod.ExportedGeneratedHeaders()...) } directSharedLibDeps = append(directSharedLibDeps, ccDep) mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName) exportDep = true case depTag == cc.CrtBeginDepTag: - depPaths.CrtBegin = linkFile + depPaths.CrtBegin = linkObject case depTag == cc.CrtEndDepTag: - depPaths.CrtEnd = linkFile + depPaths.CrtEnd = linkObject } // Make sure these dependencies are propagated if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep { lib.exportLinkDirs(linkPath) - lib.exportDepFlags(depFlag) + lib.exportLinkObjects(linkObject.String()) } } @@ -956,14 +961,6 @@ func linkPathFromFilePath(filepath android.Path) string { return strings.Split(filepath.String(), filepath.Base())[0] } -func libNameFromFilePath(filepath android.Path) string { - libName := strings.TrimSuffix(filepath.Base(), filepath.Ext()) - if strings.HasPrefix(libName, "lib") { - libName = libName[3:] - } - return libName -} - func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { ctx := &depsContext{ BottomUpMutatorContext: actx, @@ -988,8 +985,8 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { {Mutator: "rust_libraries", Variation: "dylib"}}...), dylibDepTag, deps.Dylibs...) - if deps.Rustlibs != nil { - autoDep := mod.compiler.(autoDeppable).autoDep() + if deps.Rustlibs != nil && !mod.compiler.Disabled() { + autoDep := mod.compiler.(autoDeppable).autoDep(ctx) actx.AddVariationDependencies( append(commonDepVariations, []blueprint.Variation{ {Mutator: "rust_libraries", Variation: autoDep.variation}}...), diff --git a/rust/rust_test.go b/rust/rust_test.go index 04de48b19..89ce35919 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -62,6 +62,7 @@ func testConfig(bp string) android.Config { "foo.c": nil, "src/bar.rs": nil, "src/any.h": nil, + "buf.proto": nil, "liby.so": nil, "libz.so": nil, } @@ -132,25 +133,6 @@ func testRustError(t *testing.T, pattern string, bp string) { t.Fatalf("missing expected error %q (0 errors are returned)", pattern) } -// Test that we can extract the lib name from a lib path. -func TestLibNameFromFilePath(t *testing.T) { - libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so.so") - libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so") - - libBarName := libNameFromFilePath(libBarPath) - libLibName := libNameFromFilePath(libLibPath) - - expectedResult := "bar.so" - if libBarName != expectedResult { - t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName) - } - - expectedResult = "lib.dylib" - if libLibName != expectedResult { - t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libLibPath) - } -} - // Test that we can extract the link path from a lib path. func TestLinkPathFromFilePath(t *testing.T) { barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so") diff --git a/rust/source_provider.go b/rust/source_provider.go index e168718e4..755a369a7 100644 --- a/rust/source_provider.go +++ b/rust/source_provider.go @@ -38,7 +38,7 @@ type BaseSourceProvider struct { var _ SourceProvider = (*BaseSourceProvider)(nil) type SourceProvider interface { - GenerateSource(ctx android.ModuleContext, deps PathDeps) android.Path + GenerateSource(ctx ModuleContext, deps PathDeps) android.Path Srcs() android.Paths SourceProviderProps() []interface{} SourceProviderDeps(ctx DepsContext, deps Deps) Deps @@ -49,7 +49,7 @@ func (sp *BaseSourceProvider) Srcs() android.Paths { return android.Paths{sp.OutputFile} } -func (sp *BaseSourceProvider) GenerateSource(ctx android.ModuleContext, deps PathDeps) android.Path { +func (sp *BaseSourceProvider) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path { panic("BaseSourceProviderModule does not implement GenerateSource()") } diff --git a/rust/strip.go b/rust/strip.go new file mode 100644 index 000000000..d1bbba696 --- /dev/null +++ b/rust/strip.go @@ -0,0 +1,30 @@ +// 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 rust + +import ( + "android/soong/android" + "android/soong/cc" +) + +// Stripper encapsulates cc.Stripper. +type Stripper struct { + cc.Stripper +} + +func (s *Stripper) StripExecutableOrSharedLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath) { + ccFlags := cc.StripFlags{Toolchain: ctx.RustModule().ccToolchain(ctx)} + s.Stripper.StripExecutableOrSharedLib(ctx, in, out, ccFlags) +} diff --git a/rust/test.go b/rust/test.go index 05c361e87..d93fc313f 100644 --- a/rust/test.go +++ b/rust/test.go @@ -88,7 +88,7 @@ func (test *testDecorator) compilerProps() []interface{} { return append(test.binaryDecorator.compilerProps(), &test.Properties) } -func (test *testDecorator) install(ctx ModuleContext, file android.Path) { +func (test *testDecorator) install(ctx ModuleContext) { test.testConfig = tradefed.AutoGenRustTestConfig(ctx, test.Properties.Test_config, test.Properties.Test_config_template, @@ -103,7 +103,7 @@ func (test *testDecorator) install(ctx ModuleContext, file android.Path) { ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set") } - test.binaryDecorator.install(ctx, file) + test.binaryDecorator.install(ctx) } func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { @@ -114,7 +114,7 @@ func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { return flags } -func (test *testDecorator) autoDep() autoDep { +func (test *testDecorator) autoDep(ctx BaseModuleContext) autoDep { return rlibAutoDep } diff --git a/rust/testing.go b/rust/testing.go index 80e414871..0144c8218 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -91,6 +91,12 @@ func GatherRequiredDepsForTest() string { host_supported: true, native_coverage: false, } + rust_library { + name: "libprotobuf", + crate_name: "protobuf", + srcs: ["foo.rs"], + host_supported: true, + } ` + cc.GatherRequiredDepsForTest(android.NoOsType) return bp @@ -120,6 +126,8 @@ func CreateTestContext() *android.TestContext { ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory) ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory) ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory) + ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory) + ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory) ctx.RegisterModuleType("rust_prebuilt_library", PrebuiltLibraryFactory) ctx.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory) ctx.RegisterModuleType("rust_prebuilt_rlib", PrebuiltRlibFactory) diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index 9501d88d7..8c9e2285d 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -265,11 +265,11 @@ func TestBasicSdkWithCc(t *testing.T) { } `) - sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_myapex").Rule("toc").Output - sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_shared_myapex2").Rule("toc").Output + sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_apex10000_mysdk_1").Rule("toc").Output + sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_shared_apex10000_mysdk_2").Rule("toc").Output - cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_myapex") - cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_myapex2") + cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_1") + cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_2") // Depending on the uses_sdks value, different libs are linked ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String()) @@ -340,6 +340,9 @@ func TestSnapshotWithObject(t *testing.T) { cc_object { name: "crtobj", stl: "none", + sanitize: { + never: true, + }, } `) @@ -352,6 +355,9 @@ cc_prebuilt_object { sdk_member_name: "crtobj", stl: "none", compile_multilib: "both", + sanitize: { + never: true, + }, arch: { arm64: { srcs: ["arm64/lib/crtobj.o"], @@ -367,6 +373,9 @@ cc_prebuilt_object { prefer: false, stl: "none", compile_multilib: "both", + sanitize: { + never: true, + }, arch: { arm64: { srcs: ["arm64/lib/crtobj.o"], @@ -1663,6 +1672,8 @@ func TestSnapshotWithCcLibrary(t *testing.T) { ], export_include_dirs: ["include"], stl: "none", + recovery_available: true, + vendor_available: true, } `) @@ -1674,6 +1685,8 @@ cc_prebuilt_library { name: "myexports_mynativelib@current", sdk_member_name: "mynativelib", installable: false, + recovery_available: true, + vendor_available: true, stl: "none", compile_multilib: "both", export_include_dirs: ["include/include"], @@ -1700,6 +1713,8 @@ cc_prebuilt_library { cc_prebuilt_library { name: "mynativelib", prefer: false, + recovery_available: true, + vendor_available: true, stl: "none", compile_multilib: "both", export_include_dirs: ["include/include"], diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index 931ca3c56..a7ee8d12f 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -207,8 +207,8 @@ func TestBasicSdkWithJavaLibrary(t *testing.T) { sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common").Rule("combineJar").Output sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common").Rule("combineJar").Output - javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_myapex") - javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_myapex2") + javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_1") + javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_2") // Depending on the uses_sdks value, different libs are linked ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String()) @@ -1534,7 +1534,7 @@ func TestSnapshotWithJavaSdkLibrary_NamingScheme(t *testing.T) { apex_available: ["//apex_available:anyapex"], srcs: ["Test.java"], sdk_version: "current", - naming_scheme: "framework-modules", + naming_scheme: "default", public: { enabled: true, }, @@ -1549,7 +1549,7 @@ java_sdk_library_import { name: "mysdk_myjavalib@current", sdk_member_name: "myjavalib", apex_available: ["//apex_available:anyapex"], - naming_scheme: "framework-modules", + naming_scheme: "default", shared_library: true, public: { jars: ["sdk_library/public/myjavalib-stubs.jar"], @@ -1564,7 +1564,7 @@ java_sdk_library_import { name: "myjavalib", prefer: false, apex_available: ["//apex_available:anyapex"], - naming_scheme: "framework-modules", + naming_scheme: "default", shared_library: true, public: { jars: ["sdk_library/public/myjavalib-stubs.jar"], @@ -1581,9 +1581,9 @@ sdk_snapshot { } `), checkAllCopyRules(` -.intermediates/myjavalib-stubs-publicapi/android_common/javac/myjavalib-stubs-publicapi.jar -> sdk_library/public/myjavalib-stubs.jar -.intermediates/myjavalib-stubs-srcs-publicapi/android_common/myjavalib-stubs-srcs-publicapi_api.txt -> sdk_library/public/myjavalib.txt -.intermediates/myjavalib-stubs-srcs-publicapi/android_common/myjavalib-stubs-srcs-publicapi_removed.txt -> sdk_library/public/myjavalib-removed.txt +.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar +.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt +.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt `), checkMergeZips( ".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip", diff --git a/sdk/update.go b/sdk/update.go index 936696a01..537ab13cb 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -43,7 +43,7 @@ var ( zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles", blueprint.RuleParams{ - Command: `${config.SoongZipCmd} -C $basedir -l $out.rsp -o $out`, + Command: `${config.SoongZipCmd} -C $basedir -r $out.rsp -o $out`, CommandDeps: []string{ "${config.SoongZipCmd}", }, diff --git a/sh/Android.bp b/sh/Android.bp index 0f40c5f68..e5ffeefb4 100644 --- a/sh/Android.bp +++ b/sh/Android.bp @@ -5,6 +5,7 @@ bootstrap_go_package { "blueprint", "soong", "soong-android", + "soong-cc", "soong-tradefed", ], srcs: [ diff --git a/sh/sh_binary.go b/sh/sh_binary.go index f28b2b685..f3f4a4aa7 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -17,11 +17,14 @@ package sh import ( "fmt" "path/filepath" + "sort" "strings" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/cc" "android/soong/tradefed" ) @@ -61,6 +64,12 @@ type shBinaryProperties struct { // install symlinks to the binary Symlinks []string `android:"arch_variant"` + + // Make this module available when building for ramdisk. + Ramdisk_available *bool + + // Make this module available when building for recovery. + Recovery_available *bool } type TestProperties struct { @@ -88,6 +97,20 @@ type TestProperties struct { // doesn't exist next to the Android.bp, this attribute doesn't need to be set to true // explicitly. Auto_gen_config *bool + + // list of binary modules that should be installed alongside the test + Data_bins []string `android:"path,arch_variant"` + + // list of library modules that should be installed alongside the test + Data_libs []string `android:"path,arch_variant"` + + // list of device binary modules that should be installed alongside the test. + // Only available for host sh_test modules. + Data_device_bins []string `android:"path,arch_variant"` + + // list of device library modules that should be installed alongside the test. + // Only available for host sh_test modules. + Data_device_libs []string `android:"path,arch_variant"` } type ShBinary struct { @@ -111,6 +134,8 @@ type ShTest struct { data android.Paths testConfig android.Path + + dataModules map[string]android.Path } func (s *ShBinary) HostToolPath() android.OptionalPath { @@ -139,6 +164,29 @@ func (s *ShBinary) Symlinks() []string { return s.properties.Symlinks } +var _ android.ImageInterface = (*ShBinary)(nil) + +func (s *ShBinary) ImageMutatorBegin(ctx android.BaseModuleContext) {} + +func (s *ShBinary) CoreVariantNeeded(ctx android.BaseModuleContext) bool { + return !s.ModuleBase.InstallInRecovery() && !s.ModuleBase.InstallInRamdisk() +} + +func (s *ShBinary) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool { + return proptools.Bool(s.properties.Ramdisk_available) || s.ModuleBase.InstallInRamdisk() +} + +func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool { + return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery() +} + +func (s *ShBinary) ExtraImageVariations(ctx android.BaseModuleContext) []string { + return nil +} + +func (s *ShBinary) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) { +} + func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) { s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src)) filename := proptools.String(s.properties.Filename) @@ -192,6 +240,50 @@ func (s *ShBinary) customAndroidMkEntries(entries *android.AndroidMkEntries) { } } +type dependencyTag struct { + blueprint.BaseDependencyTag + name string +} + +var ( + shTestDataBinsTag = dependencyTag{name: "dataBins"} + shTestDataLibsTag = dependencyTag{name: "dataLibs"} + shTestDataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} + shTestDataDeviceLibsTag = dependencyTag{name: "dataDeviceLibs"} +) + +var sharedLibVariations = []blueprint.Variation{{Mutator: "link", Variation: "shared"}} + +func (s *ShTest) DepsMutator(ctx android.BottomUpMutatorContext) { + s.ShBinary.DepsMutator(ctx) + + ctx.AddFarVariationDependencies(ctx.Target().Variations(), shTestDataBinsTag, s.testProperties.Data_bins...) + ctx.AddFarVariationDependencies(append(ctx.Target().Variations(), sharedLibVariations...), + shTestDataLibsTag, s.testProperties.Data_libs...) + if ctx.Target().Os.Class == android.Host && len(ctx.Config().Targets[android.Android]) > 0 { + deviceVariations := ctx.Config().Targets[android.Android][0].Variations() + ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...) + ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...), + shTestDataDeviceLibsTag, s.testProperties.Data_device_libs...) + } else if ctx.Target().Os.Class != android.Host { + if len(s.testProperties.Data_device_bins) > 0 { + ctx.PropertyErrorf("data_device_bins", "only available for host modules") + } + if len(s.testProperties.Data_device_libs) > 0 { + ctx.PropertyErrorf("data_device_libs", "only available for host modules") + } + } +} + +func (s *ShTest) addToDataModules(ctx android.ModuleContext, relPath string, path android.Path) { + if _, exists := s.dataModules[relPath]; exists { + ctx.ModuleErrorf("data modules have a conflicting installation path, %v - %s, %s", + relPath, s.dataModules[relPath].String(), path.String()) + return + } + s.dataModules[relPath] = path +} + func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { s.ShBinary.generateAndroidBuildActions(ctx) testDir := "nativetest" @@ -223,6 +315,50 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } s.testConfig = tradefed.AutoGenShellTestConfig(ctx, s.testProperties.Test_config, s.testProperties.Test_config_template, s.testProperties.Test_suites, configs, s.testProperties.Auto_gen_config, s.outputFilePath.Base()) + + s.dataModules = make(map[string]android.Path) + ctx.VisitDirectDeps(func(dep android.Module) { + depTag := ctx.OtherModuleDependencyTag(dep) + switch depTag { + case shTestDataBinsTag, shTestDataDeviceBinsTag: + if cc, isCc := dep.(*cc.Module); isCc { + s.addToDataModules(ctx, cc.OutputFile().Path().Base(), cc.OutputFile().Path()) + return + } + property := "data_bins" + if depTag == shTestDataDeviceBinsTag { + property = "data_device_bins" + } + ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) + case shTestDataLibsTag, shTestDataDeviceLibsTag: + if cc, isCc := dep.(*cc.Module); isCc { + // Copy to an intermediate output directory to append "lib[64]" to the path, + // so that it's compatible with the default rpath values. + var relPath string + if cc.Arch().ArchType.Multilib == "lib64" { + relPath = filepath.Join("lib64", cc.OutputFile().Path().Base()) + } else { + relPath = filepath.Join("lib", cc.OutputFile().Path().Base()) + } + if _, exist := s.dataModules[relPath]; exist { + return + } + relocatedLib := android.PathForModuleOut(ctx, "relocated", relPath) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: cc.OutputFile().Path(), + Output: relocatedLib, + }) + s.addToDataModules(ctx, relPath, relocatedLib) + return + } + property := "data_libs" + if depTag == shTestDataDeviceBinsTag { + property = "data_device_libs" + } + ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) + } + }) } func (s *ShTest) InstallInData() bool { @@ -251,6 +387,15 @@ func (s *ShTest) AndroidMkEntries() []android.AndroidMkEntries { path = strings.TrimSuffix(path, rel) entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel) } + relPaths := make([]string, 0) + for relPath, _ := range s.dataModules { + relPaths = append(relPaths, relPath) + } + sort.Strings(relPaths) + for _, relPath := range relPaths { + dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath) + entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath) + } }, }, }} diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go index 3bfe6110a..0aa607b6f 100644 --- a/sh/sh_binary_test.go +++ b/sh/sh_binary_test.go @@ -3,10 +3,12 @@ package sh import ( "io/ioutil" "os" + "path/filepath" "reflect" "testing" "android/soong/android" + "android/soong/cc" ) var buildDir string @@ -46,6 +48,9 @@ func testShBinary(t *testing.T, bp string) (*android.TestContext, android.Config ctx := android.NewTestArchContext() ctx.RegisterModuleType("sh_test", ShTestFactory) ctx.RegisterModuleType("sh_test_host", ShTestHostFactory) + + cc.RegisterRequiredBuildComponentsForTest(ctx) + ctx.Register(config) _, errs := ctx.ParseFileList(".", []string{"Android.bp"}) android.FailIfErrored(t, errs) @@ -105,6 +110,65 @@ func TestShTest(t *testing.T) { } } +func TestShTest_dataModules(t *testing.T) { + ctx, config := testShBinary(t, ` + sh_test { + name: "foo", + src: "test.sh", + host_supported: true, + data_bins: ["bar"], + data_libs: ["libbar"], + } + + cc_binary { + name: "bar", + host_supported: true, + shared_libs: ["libbar"], + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + + cc_library { + name: "libbar", + host_supported: true, + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + `) + + buildOS := android.BuildOs.String() + arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"} + for _, arch := range arches { + variant := ctx.ModuleForTests("foo", arch) + + libExt := ".so" + if arch == "darwin_x86_64" { + libExt = ".dylib" + } + relocated := variant.Output("relocated/lib64/libbar" + libExt) + expectedInput := filepath.Join(buildDir, ".intermediates/libbar/"+arch+"_shared/libbar"+libExt) + if relocated.Input.String() != expectedInput { + t.Errorf("Unexpected relocation input, expected: %q, actual: %q", + expectedInput, relocated.Input.String()) + } + + mod := variant.Module().(*ShTest) + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + expectedData := []string{ + filepath.Join(buildDir, ".intermediates/bar", arch, ":bar"), + filepath.Join(buildDir, ".intermediates/foo", arch, "relocated/:lib64/libbar"+libExt), + } + actualData := entries.EntryMap["LOCAL_TEST_DATA"] + if !reflect.DeepEqual(expectedData, actualData) { + t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData) + } + } +} + func TestShTestHost(t *testing.T) { ctx, _ := testShBinary(t, ` sh_test_host { @@ -124,3 +188,53 @@ func TestShTestHost(t *testing.T) { t.Errorf("host bit is not set for a sh_test_host module.") } } + +func TestShTestHost_dataDeviceModules(t *testing.T) { + ctx, config := testShBinary(t, ` + sh_test_host { + name: "foo", + src: "test.sh", + data_device_bins: ["bar"], + data_device_libs: ["libbar"], + } + + cc_binary { + name: "bar", + shared_libs: ["libbar"], + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + + cc_library { + name: "libbar", + no_libcrt: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + } + `) + + buildOS := android.BuildOs.String() + variant := ctx.ModuleForTests("foo", buildOS+"_x86_64") + + relocated := variant.Output("relocated/lib64/libbar.so") + expectedInput := filepath.Join(buildDir, ".intermediates/libbar/android_arm64_armv8-a_shared/libbar.so") + if relocated.Input.String() != expectedInput { + t.Errorf("Unexpected relocation input, expected: %q, actual: %q", + expectedInput, relocated.Input.String()) + } + + mod := variant.Module().(*ShTest) + entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0] + expectedData := []string{ + filepath.Join(buildDir, ".intermediates/bar/android_arm64_armv8-a/:bar"), + // libbar has been relocated, and so has a variant that matches the host arch. + filepath.Join(buildDir, ".intermediates/foo/"+buildOS+"_x86_64/relocated/:lib64/libbar.so"), + } + actualData := entries.EntryMap["LOCAL_TEST_DATA"] + if !reflect.DeepEqual(expectedData, actualData) { + t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData) + } +} diff --git a/tradefed/autogen.go b/tradefed/autogen.go index 798fc40fc..b35f831c7 100644 --- a/tradefed/autogen.go +++ b/tradefed/autogen.go @@ -40,9 +40,9 @@ func getTestConfig(ctx android.ModuleContext, prop *string) android.Path { } var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{ - Command: "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g' $template > $out", + Command: "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g;s&{TEST_INSTALL_BASE}&'${testInstallBase}'&g' $template > $out", CommandDeps: []string{"$template"}, -}, "name", "template", "extraConfigs", "outputFileName") +}, "name", "template", "extraConfigs", "outputFileName", "testInstallBase") func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool, testConfigTemplateProp *string) (path android.Path, autogenPath android.WritablePath) { p := getTestConfig(ctx, prop) @@ -107,15 +107,15 @@ func (ob Object) Config() string { } -func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config) { - autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "") +func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config, testInstallBase string) { + autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "", testInstallBase) } -func autogenTemplateWithName(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config) { - autogenTemplateWithNameAndOutputFile(ctx, name, output, template, configs, "") +func autogenTemplateWithName(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, testInstallBase string) { + autogenTemplateWithNameAndOutputFile(ctx, name, output, template, configs, "", testInstallBase) } -func autogenTemplateWithNameAndOutputFile(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string) { +func autogenTemplateWithNameAndOutputFile(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string, testInstallBase string) { var configStrings []string for _, config := range configs { configStrings = append(configStrings, config.Config()) @@ -128,26 +128,28 @@ func autogenTemplateWithNameAndOutputFile(ctx android.ModuleContext, name string Description: "test config", Output: output, Args: map[string]string{ - "name": name, - "template": template, - "extraConfigs": extraConfigs, - "outputFileName": outputFileName, + "name": name, + "template": template, + "extraConfigs": extraConfigs, + "outputFileName": outputFileName, + "testInstallBase": testInstallBase, }, }) } func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string, - testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path { + testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool, testInstallBase string) android.Path { + path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp) if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { - autogenTemplate(ctx, autogenPath, templatePath.String(), config) + autogenTemplate(ctx, autogenPath, templatePath.String(), config, testInstallBase) } else { if ctx.Device() { - autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}", config) + autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}", config, testInstallBase) } else { - autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}", config) + autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}", config, testInstallBase) } } return autogenPath @@ -161,9 +163,9 @@ func AutoGenShellTestConfig(ctx android.ModuleContext, testConfigProp *string, if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { - autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, templatePath.String(), config, outputFileName) + autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, templatePath.String(), config, outputFileName, "") } else { - autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, "${ShellTestConfigTemplate}", config, outputFileName) + autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, "${ShellTestConfigTemplate}", config, outputFileName, "") } return autogenPath } @@ -176,9 +178,9 @@ func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, testConfigProp if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { - autogenTemplate(ctx, autogenPath, templatePath.String(), configs) + autogenTemplate(ctx, autogenPath, templatePath.String(), configs, "") } else { - autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", configs) + autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", configs, "") } return autogenPath } @@ -191,12 +193,12 @@ func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, te if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { - autogenTemplate(ctx, autogenPath, templatePath.String(), nil) + autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "") } else { if ctx.Device() { - autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}", nil) + autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}", nil, "") } else { - autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", nil) + autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", nil, "") } } return autogenPath @@ -211,9 +213,9 @@ func AutoGenPythonBinaryHostTestConfig(ctx android.ModuleContext, testConfigProp if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { - autogenTemplate(ctx, autogenPath, templatePath.String(), nil) + autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "") } else { - autogenTemplate(ctx, autogenPath, "${PythonBinaryHostTestConfigTemplate}", nil) + autogenTemplate(ctx, autogenPath, "${PythonBinaryHostTestConfigTemplate}", nil, "") } return autogenPath } @@ -226,12 +228,12 @@ func AutoGenRustTestConfig(ctx android.ModuleContext, testConfigProp *string, if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { - autogenTemplate(ctx, autogenPath, templatePath.String(), config) + autogenTemplate(ctx, autogenPath, templatePath.String(), config, "") } else { if ctx.Device() { - autogenTemplate(ctx, autogenPath, "${RustDeviceTestConfigTemplate}", config) + autogenTemplate(ctx, autogenPath, "${RustDeviceTestConfigTemplate}", config, "") } else { - autogenTemplate(ctx, autogenPath, "${RustHostTestConfigTemplate}", config) + autogenTemplate(ctx, autogenPath, "${RustHostTestConfigTemplate}", config, "") } } return autogenPath @@ -245,9 +247,9 @@ func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *str if autogenPath != nil { templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp) if templatePath.Valid() { - autogenTemplate(ctx, autogenPath, templatePath.String(), nil) + autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "") } else { - autogenTemplate(ctx, autogenPath, "${RobolectricTestConfigTemplate}", nil) + autogenTemplate(ctx, autogenPath, "${RobolectricTestConfigTemplate}", nil, "") } return autogenPath } diff --git a/ui/build/rbe.go b/ui/build/rbe.go index 6a26063b0..c4b829d2e 100644 --- a/ui/build/rbe.go +++ b/ui/build/rbe.go @@ -19,6 +19,7 @@ import ( "math/rand" "os" "path/filepath" + "syscall" "time" "android/soong/ui/metrics" @@ -50,8 +51,25 @@ func rbeCommand(ctx Context, config Config, rbeCmd string) string { return cmdPath } -func getRBEVars(ctx Context, config Config) map[string]string { +func sockAddr(dir string) (string, error) { + maxNameLen := len(syscall.RawSockaddrUnix{}.Path) rand.Seed(time.Now().UnixNano()) + base := fmt.Sprintf("reproxy_%v.sock", rand.Intn(1000)) + + name := filepath.Join(dir, base) + if len(name) < maxNameLen { + return name, nil + } + + name = filepath.Join("/tmp", base) + if len(name) < maxNameLen { + return name, nil + } + + return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen) +} + +func getRBEVars(ctx Context, config Config) map[string]string { vars := map[string]string{ "RBE_log_path": config.rbeLogPath(), "RBE_log_dir": config.logDir(), @@ -60,7 +78,12 @@ func getRBEVars(ctx Context, config Config) map[string]string { "RBE_output_dir": config.rbeStatsOutputDir(), } if config.StartRBE() { - vars["RBE_server_address"] = fmt.Sprintf("unix://%v/reproxy_%v.sock", absPath(ctx, config.TempDir()), rand.Intn(1000)) + name, err := sockAddr(absPath(ctx, config.TempDir())) + if err != nil { + ctx.Fatalf("Error retrieving socket address: %v", err) + return nil + } + vars["RBE_server_address"] = fmt.Sprintf("unix://%v", name) } k, v := config.rbeAuth() vars[k] = v @@ -128,3 +151,13 @@ func DumpRBEMetrics(ctx Context, config Config, filename string) { ctx.Fatalf("failed to copy %q to %q: %v\n", metricsFile, filename, err) } } + +// PrintGomaDeprecation prints a PSA on the deprecation of Goma if it is set for the build. +func PrintGomaDeprecation(ctx Context, config Config) { + if config.UseGoma() { + fmt.Fprintln(ctx.Writer, "") + fmt.Fprintln(ctx.Writer, "Goma for Android is being deprecated and replaced with RBE.") + fmt.Fprintln(ctx.Writer, "See go/goma_android_deprecation for more details.") + fmt.Fprintln(ctx.Writer, "") + } +} diff --git a/zip/cmd/main.go b/zip/cmd/main.go index fba2e4b1e..d603586e6 100644 --- a/zip/cmd/main.go +++ b/zip/cmd/main.go @@ -62,6 +62,15 @@ func (listFiles) Set(s string) error { return nil } +type rspFiles struct{} + +func (rspFiles) String() string { return `""` } + +func (rspFiles) Set(s string) error { + fileArgsBuilder.RspFile(s) + return nil +} + type dir struct{} func (dir) String() string { return `""` } @@ -143,7 +152,8 @@ func main() { traceFile := flags.String("trace", "", "write trace to file") flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files") - flags.Var(&listFiles{}, "l", "file containing list of .class files") + flags.Var(&listFiles{}, "l", "file containing list of files to zip") + flags.Var(&rspFiles{}, "r", "file containing list of files to zip with Ninja rsp file escaping") flags.Var(&dir{}, "D", "directory to include in zip") flags.Var(&file{}, "f", "file to include in zip") flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression") diff --git a/zip/zip.go b/zip/zip.go index 3c710a782..e27432cbb 100644 --- a/zip/zip.go +++ b/zip/zip.go @@ -150,6 +150,30 @@ func (b *FileArgsBuilder) List(name string) *FileArgsBuilder { return b } +func (b *FileArgsBuilder) RspFile(name string) *FileArgsBuilder { + if b.err != nil { + return b + } + + f, err := b.fs.Open(name) + if err != nil { + b.err = err + return b + } + defer f.Close() + + list, err := ioutil.ReadAll(f) + if err != nil { + b.err = err + return b + } + + arg := b.state + arg.SourceFiles = ReadRespFile(list) + b.fileArgs = append(b.fileArgs, arg) + return b +} + func (b *FileArgsBuilder) Error() error { if b == nil { return nil diff --git a/zip/zip_test.go b/zip/zip_test.go index 9705d6c49..302a749a3 100644 --- a/zip/zip_test.go +++ b/zip/zip_test.go @@ -49,6 +49,9 @@ var mockFs = pathtools.MockFs(map[string][]byte{ "l_nl": []byte("a/a/a\na/a/b\nc\n"), "l_sp": []byte("a/a/a a/a/b c"), "l2": []byte("missing\n"), + "rsp": []byte("'a/a/a'\na/a/b\n'@'\n'foo'\\''bar'"), + "@ -> c": nil, + "foo'bar -> c": nil, "manifest.txt": fileCustomManifest, }) @@ -247,6 +250,19 @@ func TestZip(t *testing.T) { }, }, { + name: "rsp", + args: fileArgsBuilder(). + RspFile("rsp"), + compressionLevel: 9, + + files: []zip.FileHeader{ + fh("a/a/a", fileA, zip.Deflate), + fh("a/a/b", fileB, zip.Deflate), + fh("@", fileC, zip.Deflate), + fh("foo'bar", fileC, zip.Deflate), + }, + }, + { name: "prefix in zip", args: fileArgsBuilder(). PathPrefixInZip("foo"). @@ -568,6 +584,11 @@ func TestReadRespFile(t *testing.T) { in: `./cmd "\""-C`, out: []string{"./cmd", `"-C`}, }, + { + name: "ninja rsp file", + in: "'a'\nb\n'@'\n'foo'\\''bar'\n'foo\"bar'", + out: []string{"a", "b", "@", "foo'bar", `foo"bar`}, + }, } for _, testCase := range testCases { |