Merge "Specify module dependency in the srcs list"
diff --git a/android/config.go b/android/config.go
index 7073a49..d680b65 100644
--- a/android/config.go
+++ b/android/config.go
@@ -875,12 +875,12 @@
enforceList := c.productVariables.EnforceRROTargets
// TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency.
exemptedList := c.productVariables.EnforceRROExemptedTargets
- if exemptedList != nil {
+ if len(exemptedList) > 0 {
if InList(name, exemptedList) {
return false
}
}
- if enforceList != nil {
+ if len(enforceList) > 0 {
if InList("*", enforceList) {
return true
}
@@ -891,7 +891,7 @@
func (c *config) EnforceRROExcludedOverlay(path string) bool {
excluded := c.productVariables.EnforceRROExcludedOverlays
- if excluded != nil {
+ if len(excluded) > 0 {
return HasAnyPrefix(path, excluded)
}
return false
@@ -1059,7 +1059,7 @@
HasAnyPrefix(path, c.config.productVariables.JavaCoveragePaths) {
coverage = true
}
- if coverage && c.config.productVariables.JavaCoverageExcludePaths != nil {
+ if coverage && len(c.config.productVariables.JavaCoverageExcludePaths) > 0 {
if HasAnyPrefix(path, c.config.productVariables.JavaCoverageExcludePaths) {
coverage = false
}
@@ -1088,12 +1088,12 @@
// NativeCoveragePaths represents any path.
func (c *deviceConfig) NativeCoverageEnabledForPath(path string) bool {
coverage := false
- if c.config.productVariables.NativeCoveragePaths != nil {
+ if len(c.config.productVariables.NativeCoveragePaths) > 0 {
if InList("*", c.config.productVariables.NativeCoveragePaths) || HasAnyPrefix(path, c.config.productVariables.NativeCoveragePaths) {
coverage = true
}
}
- if coverage && c.config.productVariables.NativeCoverageExcludePaths != nil {
+ if coverage && len(c.config.productVariables.NativeCoverageExcludePaths) > 0 {
if HasAnyPrefix(path, c.config.productVariables.NativeCoverageExcludePaths) {
coverage = false
}
@@ -1164,21 +1164,21 @@
}
func (c *config) IntegerOverflowDisabledForPath(path string) bool {
- if c.productVariables.IntegerOverflowExcludePaths == nil {
+ if len(c.productVariables.IntegerOverflowExcludePaths) == 0 {
return false
}
return HasAnyPrefix(path, c.productVariables.IntegerOverflowExcludePaths)
}
func (c *config) CFIDisabledForPath(path string) bool {
- if c.productVariables.CFIExcludePaths == nil {
+ if len(c.productVariables.CFIExcludePaths) == 0 {
return false
}
return HasAnyPrefix(path, c.productVariables.CFIExcludePaths)
}
func (c *config) CFIEnabledForPath(path string) bool {
- if c.productVariables.CFIIncludePaths == nil {
+ if len(c.productVariables.CFIIncludePaths) == 0 {
return false
}
return HasAnyPrefix(path, c.productVariables.CFIIncludePaths)
diff --git a/android/module.go b/android/module.go
index 564c546..f80f37e 100644
--- a/android/module.go
+++ b/android/module.go
@@ -228,6 +228,16 @@
// For more information, see Module.GenerateBuildActions within Blueprint's module_ctx.go
GenerateAndroidBuildActions(ModuleContext)
+ // Add dependencies to the components of a module, i.e. modules that are created
+ // by the module and which are considered to be part of the creating module.
+ //
+ // This is called before prebuilts are renamed so as to allow a dependency to be
+ // added directly to a prebuilt child module instead of depending on a source module
+ // and relying on prebuilt processing to switch to the prebuilt module if preferred.
+ //
+ // A dependency on a prebuilt must include the "prebuilt_" prefix.
+ ComponentDepsMutator(ctx BottomUpMutatorContext)
+
DepsMutator(BottomUpMutatorContext)
base() *ModuleBase
@@ -769,6 +779,8 @@
prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool
}
+func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {}
+
func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {}
func (m *ModuleBase) AddProperties(props ...interface{}) {
diff --git a/android/mutator.go b/android/mutator.go
index 77d5f43..b70c4ff 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -115,6 +115,18 @@
// a DefaultableHook.
RegisterDefaultsPreArchMutators,
+ // Add dependencies on any components so that any component references can be
+ // resolved within the deps mutator.
+ //
+ // Must be run after defaults so it can be used to create dependencies on the
+ // component modules that are creating in a DefaultableHook.
+ //
+ // Must be run before RegisterPrebuiltsPreArchMutators, i.e. before prebuilts are
+ // renamed. That is so that if a module creates components using a prebuilt module
+ // type that any dependencies (which must use prebuilt_ prefixes) are resolved to
+ // the prebuilt module and not the source module.
+ RegisterComponentsMutator,
+
// Create an association between prebuilt modules and their corresponding source
// modules (if any).
//
@@ -202,6 +214,7 @@
AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module)
ReplaceDependencies(string)
+ ReplaceDependenciesIf(string, blueprint.ReplaceDependencyPredicate)
AliasVariation(variationName string)
}
@@ -252,8 +265,21 @@
return mutator
}
+func RegisterComponentsMutator(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("component-deps", componentDepsMutator).Parallel()
+}
+
+// A special mutator that runs just prior to the deps mutator to allow the dependencies
+// on component modules to be added so that they can depend directly on a prebuilt
+// module.
+func componentDepsMutator(ctx BottomUpMutatorContext) {
+ if m := ctx.Module(); m.Enabled() {
+ m.ComponentDepsMutator(ctx)
+ }
+}
+
func depsMutator(ctx BottomUpMutatorContext) {
- if m, ok := ctx.Module().(Module); ok && m.Enabled() {
+ if m := ctx.Module(); m.Enabled() {
m.DepsMutator(ctx)
}
}
@@ -403,6 +429,10 @@
b.bp.ReplaceDependencies(name)
}
+func (b *bottomUpMutatorContext) ReplaceDependenciesIf(name string, predicate blueprint.ReplaceDependencyPredicate) {
+ b.bp.ReplaceDependenciesIf(name, predicate)
+}
+
func (b *bottomUpMutatorContext) AliasVariation(variationName string) {
b.bp.AliasVariation(variationName)
}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index a29ec91..9f4df28 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -30,6 +30,16 @@
ctx.PostDepsMutators(RegisterPrebuiltsPostDepsMutators)
}
+// Marks a dependency tag as possibly preventing a reference to a source from being
+// replaced with the prebuilt.
+type ReplaceSourceWithPrebuilt interface {
+ blueprint.DependencyTag
+
+ // Return true if the dependency defined by this tag should be replaced with the
+ // prebuilt.
+ ReplaceSourceWithPrebuilt() bool
+}
+
type prebuiltDependencyTag struct {
blueprint.BaseDependencyTag
}
@@ -260,7 +270,13 @@
name := m.base().BaseModuleName()
if p.properties.UsePrebuilt {
if p.properties.SourceExists {
- ctx.ReplaceDependencies(name)
+ ctx.ReplaceDependenciesIf(name, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
+ if t, ok := tag.(ReplaceSourceWithPrebuilt); ok {
+ return t.ReplaceSourceWithPrebuilt()
+ }
+
+ return true
+ })
}
} else {
m.SkipInstall()
diff --git a/android/sdk.go b/android/sdk.go
index e823106..8115b69 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -266,6 +266,9 @@
SdkMemberType() SdkMemberType
}
+var _ SdkMemberTypeDependencyTag = (*sdkMemberDependencyTag)(nil)
+var _ ReplaceSourceWithPrebuilt = (*sdkMemberDependencyTag)(nil)
+
type sdkMemberDependencyTag struct {
blueprint.BaseDependencyTag
memberType SdkMemberType
@@ -275,6 +278,12 @@
return t.memberType
}
+// Prevent dependencies from the sdk/module_exports onto their members from being
+// replaced with a preferred prebuilt.
+func (t *sdkMemberDependencyTag) ReplaceSourceWithPrebuilt() bool {
+ return false
+}
+
func DependencyTagForSdkMemberType(memberType SdkMemberType) SdkMemberTypeDependencyTag {
return &sdkMemberDependencyTag{memberType: memberType}
}
diff --git a/apex/apex.go b/apex/apex.go
index d0c1a09..b29017d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1750,9 +1750,15 @@
return false
}
+ dt := ctx.OtherModuleDependencyTag(child)
+
+ if _, ok := dt.(android.ExcludeFromApexContentsTag); ok {
+ return false
+ }
+
// Check for the direct dependencies that contribute to the payload
- if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
- if dt.payload {
+ if adt, ok := dt.(dependencyTag); ok {
+ if adt.payload {
return do(ctx, parent, am, false /* externalDep */)
}
// As soon as the dependency graph crosses the APEX boundary, don't go further.
diff --git a/apex/apex_test.go b/apex/apex_test.go
index befb814..f064338 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -233,6 +233,7 @@
ctx.RegisterModuleType("apex_set", apexSetFactory)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(android.RegisterComponentsMutator)
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
cc.RegisterRequiredBuildComponentsForTest(ctx)
@@ -5790,6 +5791,41 @@
}
}
+func TestNonPreferredPrebuiltDependency(t *testing.T) {
+ _, _ = testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ stubs: {
+ versions: ["10000"],
+ },
+ apex_available: ["myapex"],
+ }
+
+ cc_prebuilt_library_shared {
+ name: "mylib",
+ prefer: false,
+ srcs: ["prebuilt.so"],
+ stubs: {
+ versions: ["10000"],
+ },
+ apex_available: ["myapex"],
+ }
+ `)
+}
+
func TestMain(m *testing.M) {
run := func() int {
setUp()
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 9c54399..4b9eb30 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -234,7 +234,7 @@
for _, propertyInfo := range includeDirProperties {
// Calculate the base directory in the snapshot into which the files will be copied.
// lib.ArchType is "" for common properties.
- targetDir := filepath.Join(libInfo.archType, propertyInfo.snapshotDir)
+ targetDir := filepath.Join(libInfo.OsPrefix(), libInfo.archType, propertyInfo.snapshotDir)
propertyName := propertyInfo.propertyName
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index c965107..d3802f9 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -187,6 +187,7 @@
config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
defer met.Dump(soongMetricsFile)
+ defer build.DumpRBEMetrics(buildCtx, config, rbeMetricsFile)
if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
if !strings.HasSuffix(start, "N") {
diff --git a/docs/perf.md b/docs/perf.md
index 538adff..86a27b4 100644
--- a/docs/perf.md
+++ b/docs/perf.md
@@ -12,6 +12,41 @@

+### Critical path
+
+soong_ui logs the wall time of the longest dependency chain compared to the
+elapsed wall time in `$OUT_DIR/soong.log`. For example:
+```
+critical path took 3m10s
+elapsed time 5m16s
+perfect parallelism ratio 60%
+critical path:
+ 0:00 build out/target/product/generic_arm64/obj/FAKE/sepolicy_neverallows_intermediates/policy_2.conf
+ 0:04 build out/target/product/generic_arm64/obj/FAKE/sepolicy_neverallows_intermediates/sepolicy_neverallows
+ 0:13 build out/target/product/generic_arm64/obj/ETC/plat_sepolicy.cil_intermediates/plat_sepolicy.cil
+ 0:01 build out/target/product/generic_arm64/obj/ETC/plat_pub_versioned.cil_intermediates/plat_pub_versioned.cil
+ 0:02 build out/target/product/generic_arm64/obj/ETC/vendor_sepolicy.cil_intermediates/vendor_sepolicy.cil
+ 0:16 build out/target/product/generic_arm64/obj/ETC/sepolicy_intermediates/sepolicy
+ 0:00 build out/target/product/generic_arm64/obj/ETC/plat_seapp_contexts_intermediates/plat_seapp_contexts
+ 0:00 Install: out/target/product/generic_arm64/system/etc/selinux/plat_seapp_contexts
+ 0:02 build out/target/product/generic_arm64/obj/NOTICE.txt
+ 0:00 build out/target/product/generic_arm64/obj/NOTICE.xml.gz
+ 0:00 build out/target/product/generic_arm64/system/etc/NOTICE.xml.gz
+ 0:01 Installed file list: out/target/product/generic_arm64/installed-files.txt
+ 1:00 Target system fs image: out/target/product/generic_arm64/obj/PACKAGING/systemimage_intermediates/system.img
+ 0:01 Install system fs image: out/target/product/generic_arm64/system.img
+ 0:01 Target vbmeta image: out/target/product/generic_arm64/vbmeta.img
+ 1:26 Package target files: out/target/product/generic_arm64/obj/PACKAGING/target_files_intermediates/aosp_arm64-target_files-6663974.zip
+ 0:01 Package: out/target/product/generic_arm64/aosp_arm64-img-6663974.zip
+ 0:01 Dist: /buildbot/dist_dirs/aosp-master-linux-aosp_arm64-userdebug/6663974/aosp_arm64-img-6663974.zip
+```
+
+If the elapsed time is much longer than the critical path then additional
+parallelism on the build machine will improve total build times. If there are
+long individual times listed in the critical path then improving build times
+for those steps or adjusting dependencies so that those steps can run earlier
+in the build graph will improve total build times.
+
### Soong
Soong can be traced and profiled using the standard Go tools. It understands
diff --git a/java/java_test.go b/java/java_test.go
index def42db..fb00361 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -25,7 +25,6 @@
"strings"
"testing"
- "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -86,6 +85,7 @@
RegisterStubsBuildComponents(ctx)
RegisterSdkLibraryBuildComponents(ctx)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(android.RegisterComponentsMutator)
RegisterPrebuiltApisBuildComponents(ctx)
@@ -172,20 +172,6 @@
}
}
-func checkModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
- t.Helper()
- module := ctx.ModuleForTests(name, variant).Module()
- deps := []string{}
- ctx.VisitDirectDeps(module, func(m blueprint.Module) {
- deps = append(deps, m.Name())
- })
- sort.Strings(deps)
-
- if actual := deps; !reflect.DeepEqual(expected, actual) {
- t.Errorf("expected %#q, found %#q", expected, actual)
- }
-}
-
func TestJavaLinkType(t *testing.T) {
testJava(t, `
java_library {
@@ -646,7 +632,7 @@
}
}
- checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
`prebuilt_sdklib.stubs`,
`prebuilt_sdklib.stubs.source.test`,
`prebuilt_sdklib.stubs.system`,
@@ -674,7 +660,7 @@
}
`)
- checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
`dex2oatd`,
`prebuilt_sdklib`,
`sdklib.impl`,
@@ -683,12 +669,12 @@
`sdklib.xml`,
})
- checkModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
`sdklib.impl`,
// This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
// dependency is added after prebuilts may have been renamed and so has to use
// the renamed name.
- `sdklib.stubs`,
`sdklib.xml`,
})
}
@@ -714,17 +700,16 @@
}
`)
- checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
`dex2oatd`,
`prebuilt_sdklib`,
- // This should be sdklib.stubs but is switched to the prebuilt because it is preferred.
- `prebuilt_sdklib.stubs`,
`sdklib.impl`,
+ `sdklib.stubs`,
`sdklib.stubs.source`,
`sdklib.xml`,
})
- checkModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
`prebuilt_sdklib.stubs`,
`sdklib.impl`,
`sdklib.xml`,
@@ -1491,7 +1476,7 @@
}
`)
- checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
`dex2oatd`,
`sdklib.impl`,
`sdklib.stubs`,
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 8f8f8ce..a5aa328 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -70,6 +70,12 @@
}
}
+var _ android.ReplaceSourceWithPrebuilt = (*scopeDependencyTag)(nil)
+
+func (tag scopeDependencyTag) ReplaceSourceWithPrebuilt() bool {
+ return false
+}
+
// Provides information about an api scope, e.g. public, system, test.
type apiScope struct {
// The name of the api scope, e.g. public, system, test
@@ -973,7 +979,8 @@
var implLibraryTag = sdkLibraryComponentTag{name: "impl-library"}
-func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+// Add the dependencies on the child modules in the component deps mutator.
+func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
for _, apiScope := range module.getGeneratedApiScopes(ctx) {
// Add dependencies to the stubs library
ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
@@ -998,7 +1005,12 @@
// Add dependency to the rule for generating the xml permissions file
ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlPermissionsModuleName())
}
+ }
+}
+// Add other dependencies as normal.
+func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if module.requiresRuntimeImplementationLibrary() {
// Only add the deps for the library if it is actually going to be built.
module.Library.deps(ctx)
}
@@ -1874,20 +1886,26 @@
props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
}
-func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
+// Add the dependencies on the child module in the component deps mutator so that it
+// creates references to the prebuilt and not the source modules.
+func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
for apiScope, scopeProperties := range module.scopeProperties {
if len(scopeProperties.Jars) == 0 {
continue
}
// Add dependencies to the prebuilt stubs library
- ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
+ ctx.AddVariationDependencies(nil, apiScope.stubsTag, "prebuilt_"+module.stubsLibraryModuleName(apiScope))
if len(scopeProperties.Stub_srcs) > 0 {
// Add dependencies to the prebuilt stubs source library
- ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, "prebuilt_"+module.stubsSourceModuleName(apiScope))
}
}
+}
+
+// Add other dependencies as normal.
+func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
implName := module.implLibraryModuleName()
if ctx.OtherModuleExists(implName) {
diff --git a/java/testing.go b/java/testing.go
index f5688e6..94f054e 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -16,9 +16,13 @@
import (
"fmt"
+ "reflect"
+ "sort"
+ "testing"
"android/soong/android"
"android/soong/cc"
+ "github.com/google/blueprint"
)
func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) android.Config {
@@ -216,3 +220,17 @@
return bp
}
+
+func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+ t.Helper()
+ module := ctx.ModuleForTests(name, variant).Module()
+ deps := []string{}
+ ctx.VisitDirectDeps(module, func(m blueprint.Module) {
+ deps = append(deps, m.Name())
+ })
+ sort.Strings(deps)
+
+ if actual := deps; !reflect.DeepEqual(expected, actual) {
+ t.Errorf("expected %#q, found %#q", expected, actual)
+ }
+}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 123fe70..b168cd0 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -69,6 +69,28 @@
ensureListContains(t, inputs, arm64Output.String())
}
+func TestSdkCompileMultilibOverride(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: ["sdkmember"],
+ compile_multilib: "64",
+ }
+
+ cc_library_shared {
+ name: "sdkmember",
+ srcs: ["Test.cpp"],
+ stl: "none",
+ compile_multilib: "64",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAllCopyRules(`
+.intermediates/sdkmember/android_arm64_armv8-a_shared/sdkmember.so -> arm64/lib/sdkmember.so
+`))
+}
+
func TestBasicSdkWithCc(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
@@ -79,6 +101,8 @@
cc_library_shared {
name: "sdkmember",
system_shared_libs: [],
+ stl: "none",
+ apex_available: ["mysdkapex"],
}
sdk_snapshot {
@@ -152,6 +176,13 @@
key: "myapex.key",
certificate: ":myapex.cert",
}
+
+ apex {
+ name: "mysdkapex",
+ native_shared_libs: ["sdkmember"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
`)
sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_myapex").Rule("toc").Output
@@ -1583,13 +1614,13 @@
sdk_member_name: "mynativeheaders",
host_supported: true,
stl: "none",
- export_system_include_dirs: ["include/include"],
+ export_system_include_dirs: ["common_os/include/include"],
target: {
android: {
- export_include_dirs: ["include/include-android"],
+ export_include_dirs: ["android/include/include-android"],
},
linux_glibc: {
- export_include_dirs: ["include/include-host"],
+ export_include_dirs: ["linux_glibc/include/include-host"],
},
},
}
@@ -1599,13 +1630,13 @@
prefer: false,
host_supported: true,
stl: "none",
- export_system_include_dirs: ["include/include"],
+ export_system_include_dirs: ["common_os/include/include"],
target: {
android: {
- export_include_dirs: ["include/include-android"],
+ export_include_dirs: ["android/include/include-android"],
},
linux_glibc: {
- export_include_dirs: ["include/include-host"],
+ export_include_dirs: ["linux_glibc/include/include-host"],
},
},
}
@@ -1617,9 +1648,9 @@
}
`),
checkAllCopyRules(`
-include/Test.h -> include/include/Test.h
-include-android/AndroidTest.h -> include/include-android/AndroidTest.h
-include-host/HostTest.h -> include/include-host/HostTest.h
+include/Test.h -> common_os/include/include/Test.h
+include-android/AndroidTest.h -> android/include/include-android/AndroidTest.h
+include-host/HostTest.h -> linux_glibc/include/include-host/HostTest.h
`),
)
}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 7496b20..79da3f0 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -16,6 +16,8 @@
import (
"testing"
+
+ "android/soong/java"
)
func testSdkWithJava(t *testing.T, bp string) *testSdkResult {
@@ -26,6 +28,9 @@
"resource.test": nil,
"aidl/foo/bar/Test.aidl": nil,
+ // For java_import
+ "prebuilt.jar": nil,
+
// For java_sdk_library
"api/current.txt": nil,
"api/removed.txt": nil,
@@ -85,6 +90,52 @@
// Contains tests for SDK members provided by the java package.
+func TestSdkDependsOnSourceEvenWhenPrebuiltPreferred(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ java_header_libs: ["sdkmember"],
+ }
+
+ java_library {
+ name: "sdkmember",
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+
+ java_import {
+ name: "sdkmember",
+ prefer: true,
+ jars: ["prebuilt.jar"],
+ }
+ `)
+
+ // Make sure that the mysdk module depends on "sdkmember" and not "prebuilt_sdkmember".
+ java.CheckModuleDependencies(t, result.ctx, "mysdk", "android_common", []string{"sdkmember"})
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_sdkmember@current",
+ sdk_member_name: "sdkmember",
+ jars: ["java/sdkmember.jar"],
+}
+
+java_import {
+ name: "sdkmember",
+ prefer: false,
+ jars: ["java/sdkmember.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ java_header_libs: ["mysdk_sdkmember@current"],
+}
+`))
+}
+
func TestBasicSdkWithJavaLibrary(t *testing.T) {
result := testSdkWithJava(t, `
sdk {
diff --git a/sdk/sdk.go b/sdk/sdk.go
index b9b8199..3e76008 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -218,7 +218,7 @@
Compile_multilib *string
}
p := &props{Compile_multilib: proptools.StringPtr("both")}
- ctx.AppendProperties(p)
+ ctx.PrependProperties(p)
})
return s
}
@@ -330,6 +330,11 @@
blueprint.BaseDependencyTag
}
+// Mark this tag so dependencies that use it are excluded from APEX contents.
+func (t dependencyTag) ExcludeFromApexContents() {}
+
+var _ android.ExcludeFromApexContentsTag = dependencyTag{}
+
// For dependencies from an in-development version of an SDK member to frozen versions of the same member
// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12
type sdkMemberVersionedDepTag struct {
diff --git a/sdk/testing.go b/sdk/testing.go
index 4361754..4d029e4 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -44,14 +44,15 @@
` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
mockFS := map[string][]byte{
- "build/make/target/product/security": nil,
- "apex_manifest.json": nil,
- "system/sepolicy/apex/myapex-file_contexts": nil,
- "system/sepolicy/apex/myapex2-file_contexts": nil,
- "myapex.avbpubkey": nil,
- "myapex.pem": nil,
- "myapex.x509.pem": nil,
- "myapex.pk8": nil,
+ "build/make/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "system/sepolicy/apex/myapex-file_contexts": nil,
+ "system/sepolicy/apex/myapex2-file_contexts": nil,
+ "system/sepolicy/apex/mysdkapex-file_contexts": nil,
+ "myapex.avbpubkey": nil,
+ "myapex.pem": nil,
+ "myapex.x509.pem": nil,
+ "myapex.pk8": nil,
}
cc.GatherRequiredFilesForTest(mockFS)
@@ -84,6 +85,7 @@
android.RegisterPackageBuildComponents(ctx)
ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(android.RegisterComponentsMutator)
ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 0a0bb16..4ef2721 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -63,6 +63,7 @@
"cleanbuild_test.go",
"config_test.go",
"environment_test.go",
+ "rbe_test.go",
"upload_test.go",
"util_test.go",
"proc_sync_test.go",
diff --git a/ui/build/config.go b/ui/build/config.go
index c4bbad7..e567e40 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -804,6 +804,15 @@
return true
}
+func (c *configImpl) RBEStatsOutputDir() string {
+ for _, f := range []string{"RBE_output_dir", "FLAG_output_dir"} {
+ if v, ok := c.environ.Get(f); ok {
+ return v
+ }
+ }
+ return ""
+}
+
func (c *configImpl) UseRemoteBuild() bool {
return c.UseGoma() || c.UseRBE()
}
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index ceea4bf..fcdab3b 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -15,14 +15,39 @@
package build
import (
+ "os"
"path/filepath"
"android/soong/ui/metrics"
)
-const bootstrapCmd = "bootstrap"
-const rbeLeastNProcs = 2500
-const rbeLeastNFiles = 16000
+const (
+ rbeLeastNProcs = 2500
+ rbeLeastNFiles = 16000
+
+ // prebuilt RBE binaries
+ bootstrapCmd = "bootstrap"
+
+ // RBE metrics proto buffer file
+ rbeMetricsPBFilename = "rbe_metrics.pb"
+)
+
+func rbeCommand(ctx Context, config Config, rbeCmd string) string {
+ var cmdPath string
+ if rbeDir, ok := config.Environment().Get("RBE_DIR"); ok {
+ cmdPath = filepath.Join(rbeDir, rbeCmd)
+ } else if home, ok := config.Environment().Get("HOME"); ok {
+ cmdPath = filepath.Join(home, "rbe", rbeCmd)
+ } else {
+ ctx.Fatalf("rbe command path not found")
+ }
+
+ if _, err := os.Stat(cmdPath); err != nil && os.IsNotExist(err) {
+ ctx.Fatalf("rbe command %q not found", rbeCmd)
+ }
+
+ return cmdPath
+}
func startRBE(ctx Context, config Config) {
ctx.BeginTrace(metrics.RunSetupTool, "rbe_bootstrap")
@@ -35,18 +60,50 @@
ctx.Fatalf("max open files is insufficient: %d; want >= %d.\n", n, rbeLeastNFiles)
}
- var rbeBootstrap string
- if rbeDir, ok := config.Environment().Get("RBE_DIR"); ok {
- rbeBootstrap = filepath.Join(rbeDir, bootstrapCmd)
- } else if home, ok := config.Environment().Get("HOME"); ok {
- rbeBootstrap = filepath.Join(home, "rbe", bootstrapCmd)
- } else {
- ctx.Fatalln("rbe bootstrap not found")
- }
-
- cmd := Command(ctx, config, "boostrap", rbeBootstrap)
+ cmd := Command(ctx, config, "startRBE bootstrap", rbeCommand(ctx, config, bootstrapCmd))
if output, err := cmd.CombinedOutput(); err != nil {
ctx.Fatalf("rbe bootstrap failed with: %v\n%s\n", err, output)
}
}
+
+func stopRBE(ctx Context, config Config) {
+ cmd := Command(ctx, config, "stopRBE bootstrap", rbeCommand(ctx, config, bootstrapCmd), "-shutdown")
+ if output, err := cmd.CombinedOutput(); err != nil {
+ ctx.Fatalf("rbe bootstrap with shutdown failed with: %v\n%s\n", err, output)
+ }
+}
+
+// DumpRBEMetrics creates a metrics protobuf file containing RBE related metrics.
+// The protobuf file is created if RBE is enabled and the proxy service has
+// started. The proxy service is shutdown in order to dump the RBE metrics to the
+// protobuf file.
+func DumpRBEMetrics(ctx Context, config Config, filename string) {
+ ctx.BeginTrace(metrics.RunShutdownTool, "dump_rbe_metrics")
+ defer ctx.EndTrace()
+
+ // Remove the previous metrics file in case there is a failure or RBE has been
+ // disable for this run.
+ os.Remove(filename)
+
+ // If RBE is not enabled then there are no metrics to generate.
+ // If RBE does not require to start, the RBE proxy maybe started
+ // manually for debugging purpose and can generate the metrics
+ // afterwards.
+ if !config.StartRBE() {
+ return
+ }
+
+ outputDir := config.RBEStatsOutputDir()
+ if outputDir == "" {
+ ctx.Fatal("RBE output dir variable not defined. Aborting metrics dumping.")
+ }
+ metricsFile := filepath.Join(outputDir, rbeMetricsPBFilename)
+
+ // Stop the proxy first in order to generate the RBE metrics protobuf file.
+ stopRBE(ctx, config)
+
+ if _, err := copyFile(metricsFile, filename); err != nil {
+ ctx.Fatalf("failed to copy %q to %q: %v\n", metricsFile, filename, err)
+ }
+}
diff --git a/ui/build/rbe_test.go b/ui/build/rbe_test.go
new file mode 100644
index 0000000..2c4995b
--- /dev/null
+++ b/ui/build/rbe_test.go
@@ -0,0 +1,142 @@
+// 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 build
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "android/soong/ui/logger"
+)
+
+func TestDumpRBEMetrics(t *testing.T) {
+ ctx := testContext()
+ tests := []struct {
+ description string
+ env []string
+ generated bool
+ }{{
+ description: "RBE disabled",
+ env: []string{
+ "NOSTART_RBE=true",
+ },
+ }, {
+ description: "rbe metrics generated",
+ env: []string{
+ "USE_RBE=true",
+ },
+ generated: true,
+ }}
+
+ for _, tt := range tests {
+ t.Run(tt.description, func(t *testing.T) {
+ tmpDir := t.TempDir()
+
+ rbeBootstrapCmd := filepath.Join(tmpDir, bootstrapCmd)
+ if err := ioutil.WriteFile(rbeBootstrapCmd, []byte(rbeBootstrapProgram), 0755); err != nil {
+ t.Fatalf("failed to create a fake bootstrap command file %s: %v", rbeBootstrapCmd, err)
+ }
+
+ env := Environment(tt.env)
+ env.Set("OUT_DIR", tmpDir)
+ env.Set("RBE_DIR", tmpDir)
+ env.Set("RBE_output_dir", t.TempDir())
+ config := Config{&configImpl{
+ environ: &env,
+ }}
+
+ rbeMetricsFilename := filepath.Join(tmpDir, rbeMetricsPBFilename)
+ DumpRBEMetrics(ctx, config, rbeMetricsFilename)
+
+ // Validate that the rbe metrics file exists if RBE is enabled.
+ if _, err := os.Stat(rbeMetricsFilename); err == nil {
+ if !tt.generated {
+ t.Errorf("got true, want false for rbe metrics file %s to exist.", rbeMetricsFilename)
+ }
+ } else if os.IsNotExist(err) {
+ if tt.generated {
+ t.Errorf("got false, want true for rbe metrics file %s to exist.", rbeMetricsFilename)
+ }
+ } else {
+ t.Errorf("unknown error found on checking %s exists: %v", rbeMetricsFilename, err)
+ }
+ })
+ }
+}
+
+func TestDumpRBEMetricsErrors(t *testing.T) {
+ ctx := testContext()
+ tests := []struct {
+ description string
+ rbeOutputDirDefined bool
+ bootstrapProgram string
+ expectedErr string
+ }{{
+ description: "output_dir not defined",
+ bootstrapProgram: rbeBootstrapProgram,
+ expectedErr: "RBE output dir variable not defined",
+ }, {
+ description: "stopRBE failed",
+ rbeOutputDirDefined: true,
+ bootstrapProgram: "#!/bin/bash\nexit 1",
+ expectedErr: "shutdown failed",
+ }, {
+ description: "failed to copy metrics file",
+ rbeOutputDirDefined: true,
+ bootstrapProgram: "#!/bin/bash",
+ expectedErr: "failed to copy",
+ }}
+
+ for _, tt := range tests {
+ t.Run(tt.description, func(t *testing.T) {
+ defer logger.Recover(func(err error) {
+ got := err.Error()
+ if !strings.Contains(got, tt.expectedErr) {
+ t.Errorf("got %q, want %q to be contained in error", got, tt.expectedErr)
+ }
+ })
+
+ tmpDir := t.TempDir()
+
+ rbeBootstrapCmd := filepath.Join(tmpDir, bootstrapCmd)
+ if err := ioutil.WriteFile(rbeBootstrapCmd, []byte(tt.bootstrapProgram), 0755); err != nil {
+ t.Fatalf("failed to create a fake bootstrap command file %s: %v", rbeBootstrapCmd, err)
+ }
+
+ env := &Environment{}
+ env.Set("USE_RBE", "true")
+ env.Set("OUT_DIR", tmpDir)
+ env.Set("RBE_DIR", tmpDir)
+
+ if tt.rbeOutputDirDefined {
+ env.Set("RBE_output_dir", t.TempDir())
+ }
+
+ config := Config{&configImpl{
+ environ: env,
+ }}
+
+ rbeMetricsFilename := filepath.Join(tmpDir, rbeMetricsPBFilename)
+ DumpRBEMetrics(ctx, config, rbeMetricsFilename)
+ t.Errorf("got nil, expecting %q as a failure", tt.expectedErr)
+ })
+ }
+}
+
+var rbeBootstrapProgram = fmt.Sprintf("#!/bin/bash\necho 1 > $RBE_output_dir/%s", rbeMetricsPBFilename)
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 3e76d37..e055b76 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -25,12 +25,13 @@
)
const (
- RunSetupTool = "setup"
- RunKati = "kati"
- RunSoong = "soong"
- PrimaryNinja = "ninja"
- TestRun = "test"
- Total = "total"
+ PrimaryNinja = "ninja"
+ RunKati = "kati"
+ RunSetupTool = "setup"
+ RunShutdownTool = "shutdown"
+ RunSoong = "soong"
+ TestRun = "test"
+ Total = "total"
)
type Metrics struct {