Merge "Inclusive fix: Replace sanity with validation in cc.go."
diff --git a/android/Android.bp b/android/Android.bp
index 6ddcc14..50faa44 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -24,6 +24,7 @@
         "filegroup.go",
         "hooks.go",
         "image.go",
+        "makefile_goal.go",
         "makevars.go",
         "metrics.go",
         "module.go",
diff --git a/android/config.go b/android/config.go
index cafc71b..aeed81d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -337,8 +337,8 @@
 		config: config,
 	}
 
-	// Sanity check the build and source directories. This won't catch strange
-	// configurations with symlinks, but at least checks the obvious cases.
+	// Soundness check of the build and source directories. This won't catch strange
+	// configurations with symlinks, but at least checks the obvious case.
 	absBuildDir, err := filepath.Abs(buildDir)
 	if err != nil {
 		return Config{}, err
diff --git a/android/makefile_goal.go b/android/makefile_goal.go
new file mode 100644
index 0000000..eae3976
--- /dev/null
+++ b/android/makefile_goal.go
@@ -0,0 +1,99 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"fmt"
+	"io"
+	"path/filepath"
+
+	"github.com/google/blueprint/proptools"
+)
+
+func init() {
+	RegisterModuleType("makefile_goal", MakefileGoalFactory)
+}
+
+type makefileGoalProperties struct {
+	// Sources.
+
+	// Makefile goal output file path, relative to PRODUCT_OUT.
+	Product_out_path *string
+}
+
+type makefileGoal struct {
+	ModuleBase
+
+	properties makefileGoalProperties
+
+	// Destination. Output file path of this module.
+	outputFilePath OutputPath
+}
+
+var _ AndroidMkEntriesProvider = (*makefileGoal)(nil)
+var _ OutputFileProducer = (*makefileGoal)(nil)
+
+// Input file of this makefile_goal module. Nil if none specified. May use variable names in makefiles.
+func (p *makefileGoal) inputPath() *string {
+	if p.properties.Product_out_path != nil {
+		return proptools.StringPtr(filepath.Join("$(PRODUCT_OUT)", proptools.String(p.properties.Product_out_path)))
+	}
+	return nil
+}
+
+// OutputFileProducer
+func (p *makefileGoal) OutputFiles(tag string) (Paths, error) {
+	if tag != "" {
+		return nil, fmt.Errorf("unsupported tag %q", tag)
+	}
+	return Paths{p.outputFilePath}, nil
+}
+
+// AndroidMkEntriesProvider
+func (p *makefileGoal) DepsMutator(ctx BottomUpMutatorContext) {
+	if p.inputPath() == nil {
+		ctx.PropertyErrorf("product_out_path", "Path relative to PRODUCT_OUT required")
+	}
+}
+
+func (p *makefileGoal) GenerateAndroidBuildActions(ctx ModuleContext) {
+	filename := filepath.Base(proptools.String(p.inputPath()))
+	p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
+
+	ctx.InstallFile(PathForModuleInstall(ctx, "etc"), ctx.ModuleName(), p.outputFilePath)
+}
+
+func (p *makefileGoal) AndroidMkEntries() []AndroidMkEntries {
+	return []AndroidMkEntries{AndroidMkEntries{
+		Class:      "ETC",
+		OutputFile: OptionalPathForPath(p.outputFilePath),
+		ExtraFooters: []AndroidMkExtraFootersFunc{
+			func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries) {
+				// Can't use Cp because inputPath() is not a valid Path.
+				fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath)
+			},
+		},
+	}}
+}
+
+// Import a Makefile goal to Soong by copying the file built by
+// the goal to a path visible to Soong. This rule only works on boot images.
+func MakefileGoalFactory() Module {
+	module := &makefileGoal{}
+	module.AddProperties(&module.properties)
+	// This module is device-only
+	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
+	return module
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index 526d399..73829f1 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -56,6 +56,7 @@
 	AddNeverAllowRules(createJavaDeviceForHostRules()...)
 	AddNeverAllowRules(createCcSdkVariantRules()...)
 	AddNeverAllowRules(createUncompressDexRules()...)
+	AddNeverAllowRules(createMakefileGoalRules()...)
 }
 
 // Add a NeverAllow rule to the set of rules to apply.
@@ -231,6 +232,15 @@
 	}
 }
 
+func createMakefileGoalRules() []Rule {
+	return []Rule{
+		NeverAllow().
+			ModuleType("makefile_goal").
+			WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
+			Because("Only boot images may be imported as a makefile goal."),
+	}
+}
+
 func neverallowMutator(ctx BottomUpMutatorContext) {
 	m, ok := ctx.Module().(Module)
 	if !ok {
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 45d36a6..56a07dc 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -326,6 +326,20 @@
 			"module \"outside_art_libraries\": violates neverallow",
 		},
 	},
+	{
+		name: "disallowed makefile_goal",
+		fs: map[string][]byte{
+			"Android.bp": []byte(`
+				makefile_goal {
+					name: "foo",
+					product_out_path: "boot/trap.img"
+				}
+			`),
+		},
+		expectedErrors: []string{
+			"Only boot images may be imported as a makefile goal.",
+		},
+	},
 }
 
 func TestNeverallow(t *testing.T) {
@@ -350,6 +364,7 @@
 	ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
 	ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
 	ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
+	ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule)
 	ctx.PostDepsMutators(RegisterNeverallowMutator)
 	ctx.Register(config)
 
@@ -438,3 +453,22 @@
 
 func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
 }
+
+type mockMakefileGoalProperties struct {
+	Product_out_path *string
+}
+
+type mockMakefileGoalModule struct {
+	ModuleBase
+	properties mockMakefileGoalProperties
+}
+
+func newMockMakefileGoalModule() Module {
+	m := &mockMakefileGoalModule{}
+	m.AddProperties(&m.properties)
+	InitAndroidModule(m)
+	return m
+}
+
+func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) {
+}
diff --git a/apex/apex.go b/apex/apex.go
index 1cfb583..e3a95fa 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -691,14 +691,27 @@
 		MinSdkVersion: a.minSdkVersion(mctx),
 		Updatable:     a.Updatable(),
 	}
+
+	useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface())
+	excludeVndkLibs := useVndk && proptools.Bool(a.properties.Use_vndk_as_stable)
+	if !useVndk && proptools.Bool(a.properties.Use_vndk_as_stable) {
+		mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes")
+		return
+	}
+
 	mctx.WalkDeps(func(child, parent android.Module) bool {
 		am, ok := child.(android.ApexModule)
 		if !ok || !am.CanHaveApexVariants() {
 			return false
 		}
-		if !parent.(android.DepIsInSameApex).DepIsInSameApex(mctx, child) && !inAnySdk(child) {
+		if !parent.(android.DepIsInSameApex).DepIsInSameApex(mctx, child) {
 			return false
 		}
+		if excludeVndkLibs {
+			if c, ok := child.(*cc.Module); ok && c.IsVndk() {
+				return false
+			}
+		}
 
 		depName := mctx.OtherModuleName(child)
 		// If the parent is apexBundle, this child is directly depended.
@@ -1009,6 +1022,11 @@
 
 	// The minimum SDK version that this apex must be compatibile with.
 	Min_sdk_version *string
+
+	// If set true, VNDK libs are considered as stable libs and are not included in this apex.
+	// Should be only used in non-system apexes (e.g. vendor: true).
+	// Default is false.
+	Use_vndk_as_stable *bool
 }
 
 type apexTargetBundleProperties struct {
@@ -1826,7 +1844,8 @@
 
 	// Because APEXes targeting other than system/system_ext partitions
 	// can't set apex_available, we skip checks for these APEXes
-	if ctx.SocSpecific() || ctx.DeviceSpecific() || ctx.ProductSpecific() {
+	if a.SocSpecific() || a.DeviceSpecific() ||
+		(a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
 		return
 	}
 
@@ -2142,6 +2161,13 @@
 							// don't include it in this APEX
 							return false
 						}
+						if cc.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && cc.IsVndk() {
+							// For vendor APEX with use_vndk_as_stable: true, we don't include VNDK libs
+							// and use them from VNDK APEX.
+							// TODO(b/159576928): add "vndk" as requiredDeps so that linkerconfig can make "vndk"
+							// linker namespace avaiable to this apex.
+							return false
+						}
 						af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
 						af.transitiveDep = true
 						if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
@@ -2259,7 +2285,8 @@
 
 	// APEXes targeting other than system/system_ext partitions use vendor/product variants.
 	// So we can't link them to /system/lib libs which are core variants.
-	if a.SocSpecific() || a.DeviceSpecific() || a.ProductSpecific() {
+	if a.SocSpecific() || a.DeviceSpecific() ||
+		(a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
 		a.linkToSystemLib = false
 	}
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 3600614..7db61d5 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2203,6 +2203,55 @@
 	ensureContains(t, androidMk, `LOCAL_MODULE_PATH := /tmp/target/product/test_device/vendor/apex`)
 }
 
+func TestVendorApex_use_vndk_as_stable(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			binaries: ["mybin"],
+			vendor: true,
+			use_vndk_as_stable: true,
+		}
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+		cc_binary {
+			name: "mybin",
+			vendor: true,
+			shared_libs: ["libvndk", "libvendor"],
+		}
+		cc_library {
+			name: "libvndk",
+			vndk: {
+				enabled: true,
+			},
+			vendor_available: true,
+		}
+		cc_library {
+			name: "libvendor",
+			vendor: true,
+		}
+	`)
+
+	vendorVariant := "android_vendor.VER_arm64_armv8-a"
+
+	ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_myapex").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")
+
+	// VNDK libs are not included when use_vndk_as_stable: true
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+		"bin/mybin",
+		"lib64/libvendor.so",
+	})
+}
+
 func TestAndroidMk_UseVendorRequired(t *testing.T) {
 	ctx, config := testApex(t, `
 		apex {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 4578fd3..22e3ec3 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -396,8 +396,8 @@
 	return module
 }
 
-// ndk_library creates a stub library that exposes dummy implementation
-// of functions and variables for use at build time only.
+// ndk_library creates a library that exposes a stub implementation of functions
+// and variables for use at build time only.
 func NdkLibraryFactory() android.Module {
 	module := newStubLibrary()
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 3848148..300bc8f 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -174,6 +174,8 @@
 
 		// value to pass to -fsanitize-blacklist
 		Blacklist *string
+		// value to pass to -fsanitize-blacklist
+		Blocklist *string
 	} `android:"arch_variant"`
 
 	SanitizerEnabled  bool     `blueprint:"mutated"`
@@ -596,6 +598,12 @@
 		flags.CFlagsDeps = append(flags.CFlagsDeps, blacklist.Path())
 	}
 
+	blocklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blocklist)
+	if blocklist.Valid() {
+		flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-blacklist="+blocklist.String())
+		flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path())
+	}
+
 	return flags
 }
 
diff --git a/cc/vndk.go b/cc/vndk.go
index 15843c6..f9adec7 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -340,7 +340,7 @@
 	}
 }
 
-// Sanity check for modules that mustn't be VNDK
+// Check for modules that mustn't be VNDK
 func shouldSkipVndkMutator(m *Module) bool {
 	if !m.Enabled() {
 		return true
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index e485c60..69e4f69 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -35,14 +35,14 @@
 // A command represents an operation to be executed in the soong build
 // system.
 type command struct {
-	// the flag name (must have double dashes)
+	// The flag name (must have double dashes).
 	flag string
 
-	// description for the flag (to display when running help)
+	// Description for the flag (to display when running help).
 	description string
 
-	// Forces the status output into dumb terminal mode.
-	forceDumbOutput bool
+	// Stream the build status output into the simple terminal mode.
+	simpleOutput bool
 
 	// Sets a prefix string to use for filenames of log files.
 	logsPrefix string
@@ -70,21 +70,21 @@
 		stdio: stdio,
 		run:   make,
 	}, {
-		flag:            "--dumpvar-mode",
-		description:     "print the value of the legacy make variable VAR to stdout",
-		forceDumbOutput: true,
-		logsPrefix:      "dumpvars-",
-		config:          dumpVarConfig,
-		stdio:           customStdio,
-		run:             dumpVar,
+		flag:         "--dumpvar-mode",
+		description:  "print the value of the legacy make variable VAR to stdout",
+		simpleOutput: true,
+		logsPrefix:   "dumpvars-",
+		config:       dumpVarConfig,
+		stdio:        customStdio,
+		run:          dumpVar,
 	}, {
-		flag:            "--dumpvars-mode",
-		description:     "dump the values of one or more legacy make variables, in shell syntax",
-		forceDumbOutput: true,
-		logsPrefix:      "dumpvars-",
-		config:          dumpVarConfig,
-		stdio:           customStdio,
-		run:             dumpVars,
+		flag:         "--dumpvars-mode",
+		description:  "dump the values of one or more legacy make variables, in shell syntax",
+		simpleOutput: true,
+		logsPrefix:   "dumpvars-",
+		config:       dumpVarConfig,
+		stdio:        customStdio,
+		run:          dumpVars,
 	}, {
 		flag:        "--build-mode",
 		description: "build modules based on the specified build action",
@@ -125,7 +125,7 @@
 		os.Exit(1)
 	}
 
-	output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.forceDumbOutput,
+	output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.simpleOutput,
 		build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
 
 	log := logger.New(output)
@@ -172,7 +172,7 @@
 	buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
 	rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
 	soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
-	defer build.UploadMetrics(buildCtx, config, c.forceDumbOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
+	defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
 
 	os.MkdirAll(logsDir, 0777)
 	log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 00baa57..1cec289 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -259,9 +259,9 @@
 
 		// If AllowMissingDependencies is enabled, the build will not have stopped when
 		// AddFarVariationDependencies was called on a missing tool, which will result in nonsensical
-		// "cmd: unknown location label ..." errors later.  Add a dummy file to the local label.  The
-		// command that uses this dummy file will never be executed because the rule will be replaced with
-		// an android.Error rule reporting the missing dependencies.
+		// "cmd: unknown location label ..." errors later.  Add a placeholder file to the local label.
+		// The command that uses this placeholder file will never be executed because the rule will be
+		// replaced with an android.Error rule reporting the missing dependencies.
 		if ctx.Config().AllowMissingDependencies() {
 			for _, tool := range g.properties.Tools {
 				if !seenTools[tool] {
@@ -292,9 +292,9 @@
 
 			// If AllowMissingDependencies is enabled, the build will not have stopped when
 			// the dependency was added on a missing SourceFileProducer module, which will result in nonsensical
-			// "cmd: label ":..." has no files" errors later.  Add a dummy file to the local label.  The
-			// command that uses this dummy file will never be executed because the rule will be replaced with
-			// an android.Error rule reporting the missing dependencies.
+			// "cmd: label ":..." has no files" errors later.  Add a placeholder file to the local label.
+			// The command that uses this placeholder file will never be executed because the rule will be
+			// replaced with an android.Error rule reporting the missing dependencies.
 			ctx.AddMissingDependencies(missingDeps)
 			addLocationLabel(in, []string{"***missing srcs " + in + "***"})
 		} else {
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 190a052..935b839 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1674,7 +1674,7 @@
 
 	impRule := android.NewRuleBuilder()
 	impCmd := impRule.Command()
-	// A dummy action that copies the ninja generated rsp file to a new location. This allows us to
+	// An action that copies the ninja generated rsp file to a new location. This allows us to
 	// add a large number of inputs to a file without exceeding bash command length limits (which
 	// would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the
 	// rsp file to be ${output}.rsp.
diff --git a/java/java_test.go b/java/java_test.go
index 73e6792..582ebe9 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -489,7 +489,7 @@
 
 	ctx, _ := testJavaWithConfig(t, config)
 
-	// first, sanity check that the -g flag is added to target modules
+	// first, check that the -g flag is added to target modules
 	targetLibrary := ctx.ModuleForTests("target_library", "android_common")
 	targetJavaFlags := targetLibrary.Module().VariablesForTests()["javacFlags"]
 	if !strings.Contains(targetJavaFlags, "-g:source,lines") {
diff --git a/java/lint.go b/java/lint.go
index 6391067..1bf7f69 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -252,7 +252,7 @@
 	return projectXMLPath, configXMLPath, cacheDir, homeDir, deps
 }
 
-// generateManifest adds a command to the rule to write a dummy manifest cat contains the
+// generateManifest adds a command to the rule to write a simple manifest that contains the
 // minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
 func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path {
 	manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
diff --git a/java/sdk.go b/java/sdk.go
index 6e67a13..5d79d1d 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -214,7 +214,7 @@
 		// "current" can be built from source and be from prebuilt SDK
 		return ctx.Config().UnbundledBuildUsePrebuiltSdks()
 	} else if s.version.isNumbered() {
-		// sanity check
+		// validation check
 		if s.kind != sdkPublic && s.kind != sdkSystem && s.kind != sdkTest {
 			panic(fmt.Errorf("prebuilt SDK is not not available for sdkKind=%q", s.kind))
 			return false
diff --git a/rust/binary.go b/rust/binary.go
index 1e9e119..1a82c92 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -86,7 +86,7 @@
 	deps = binary.baseCompiler.compilerDeps(ctx, deps)
 
 	if ctx.toolchain().Bionic() {
-		deps = binary.baseCompiler.bionicDeps(ctx, deps)
+		deps = bionicDeps(deps)
 		deps.CrtBegin = "crtbegin_dynamic"
 		deps.CrtEnd = "crtend_android"
 	}
diff --git a/rust/bindgen.go b/rust/bindgen.go
index 83ad560..e8bbb35 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -15,11 +15,11 @@
 package rust
 
 import (
-	"github.com/google/blueprint"
 	"strings"
 
+	"github.com/google/blueprint"
+
 	"android/soong/android"
-	"android/soong/cc"
 	ccConfig "android/soong/cc/config"
 )
 
@@ -41,8 +41,10 @@
 	bindgen = pctx.AndroidStaticRule("bindgen",
 		blueprint.RuleParams{
 			Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " +
-				"$bindgenCmd $flags $in -o $out -- $cflags",
+				"$bindgenCmd $flags $in -o $out -- -MD -MF $out.d $cflags",
 			CommandDeps: []string{"$bindgenCmd"},
+			Deps:        blueprint.DepsGCC,
+			Depfile:     "$out.d",
 		},
 		"flags", "cflags")
 )
@@ -83,40 +85,39 @@
 	Properties BindgenProperties
 }
 
-func (b *bindgenDecorator) libraryExports(ctx android.ModuleContext) (android.Paths, []string) {
-	var libraryPaths android.Paths
-	var libraryFlags []string
-
-	for _, static_lib := range b.Properties.Static_libs {
-		if dep, ok := ctx.GetDirectDepWithTag(static_lib, cc.StaticDepTag).(*cc.Module); ok {
-			libraryPaths = append(libraryPaths, dep.ExportedIncludeDirs()...)
-			libraryFlags = append(libraryFlags, dep.ExportedFlags()...)
-		}
-	}
-	for _, shared_lib := range b.Properties.Shared_libs {
-		if dep, ok := ctx.GetDirectDepWithTag(shared_lib, cc.SharedDepTag).(*cc.Module); ok {
-			libraryPaths = append(libraryPaths, dep.ExportedIncludeDirs()...)
-			libraryFlags = append(libraryFlags, dep.ExportedFlags()...)
-		}
-	}
-
-	return libraryPaths, libraryFlags
-}
-
-func (b *bindgenDecorator) generateSource(ctx android.ModuleContext) android.Path {
+func (b *bindgenDecorator) generateSource(ctx android.ModuleContext, deps PathDeps) android.Path {
 	ccToolchain := ccConfig.FindToolchain(ctx.Os(), ctx.Arch())
-	includes, exportedFlags := b.libraryExports(ctx)
 
 	var cflags []string
-	cflags = append(cflags, b.Properties.Cflags...)
+	var implicits android.Paths
+
+	implicits = append(implicits, deps.depIncludePaths...)
+	implicits = append(implicits, deps.depSystemIncludePaths...)
+
+	// Default clang flags
+	cflags = append(cflags, "${ccConfig.CommonClangGlobalCflags}")
+	if ctx.Device() {
+		cflags = append(cflags, "${ccConfig.DeviceClangGlobalCflags}")
+	}
+
+	// Toolchain clang flags
 	cflags = append(cflags, "-target "+ccToolchain.ClangTriple())
 	cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${ccConfig."))
-	cflags = append(cflags, exportedFlags...)
-	for _, include := range includes {
+
+	// Dependency clang flags and include paths
+	cflags = append(cflags, deps.depClangFlags...)
+	for _, include := range deps.depIncludePaths {
 		cflags = append(cflags, "-I"+include.String())
 	}
+	for _, include := range deps.depSystemIncludePaths {
+		cflags = append(cflags, "-isystem "+include.String())
+	}
+
+	// Module defined clang flags and include paths
+	cflags = append(cflags, b.Properties.Cflags...)
 	for _, include := range b.Properties.Local_include_dirs {
 		cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String())
+		implicits = append(implicits, android.PathForModuleSrc(ctx, include))
 	}
 
 	bindgenFlags := defaultBindgenFlags
@@ -134,7 +135,7 @@
 		Description: "bindgen " + wrapperFile.Path().Rel(),
 		Output:      outputFile,
 		Input:       wrapperFile.Path(),
-		Implicits:   includes,
+		Implicits:   implicits,
 		Args: map[string]string{
 			"flags":  strings.Join(bindgenFlags, " "),
 			"cflags": strings.Join(cflags, " "),
@@ -176,6 +177,10 @@
 
 func (b *bindgenDecorator) sourceProviderDeps(ctx DepsContext, deps Deps) Deps {
 	deps = b.baseSourceProvider.sourceProviderDeps(ctx, deps)
+	if ctx.toolchain().Bionic() {
+		deps = bionicDeps(deps)
+	}
+
 	deps.SharedLibs = append(deps.SharedLibs, b.Properties.Shared_libs...)
 	deps.StaticLibs = append(deps.StaticLibs, b.Properties.Static_libs...)
 	return deps
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
index 18e188f..2122ec1 100644
--- a/rust/bindgen_test.go
+++ b/rust/bindgen_test.go
@@ -48,9 +48,9 @@
 		t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
 	}
 	if !strings.Contains(libbindgen.Args["cflags"], "-Ishared_include") {
-		t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+		t.Errorf("missing shared_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
 	}
 	if !strings.Contains(libbindgen.Args["cflags"], "-Istatic_include") {
-		t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+		t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
 	}
 }
diff --git a/rust/compiler.go b/rust/compiler.go
index ab3d2f4..040219d 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -199,7 +199,7 @@
 	return deps
 }
 
-func (compiler *baseCompiler) bionicDeps(ctx DepsContext, deps Deps) Deps {
+func bionicDeps(deps Deps) Deps {
 	deps.SharedLibs = append(deps.SharedLibs, "liblog")
 	deps.SharedLibs = append(deps.SharedLibs, "libc")
 	deps.SharedLibs = append(deps.SharedLibs, "libm")
diff --git a/rust/library.go b/rust/library.go
index ac725d7..4c6da9d 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -340,7 +340,7 @@
 	deps = library.baseCompiler.compilerDeps(ctx, deps)
 
 	if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) {
-		deps = library.baseCompiler.bionicDeps(ctx, deps)
+		deps = bionicDeps(deps)
 		deps.CrtBegin = "crtbegin_so"
 		deps.CrtEnd = "crtend_so"
 	}
diff --git a/rust/rust.go b/rust/rust.go
index 89b89e2..78bf7ad 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -256,6 +256,11 @@
 	depFlags   []string
 	//ReexportedDeps android.Paths
 
+	// Used by bindgen modules which call clang
+	depClangFlags         []string
+	depIncludePaths       android.Paths
+	depSystemIncludePaths android.Paths
+
 	coverageFiles android.Paths
 
 	CrtBegin android.OptionalPath
@@ -671,7 +676,7 @@
 			mod.compiler.install(ctx, mod.outputFile.Path())
 		}
 	} else if mod.sourceProvider != nil {
-		outputFile := mod.sourceProvider.generateSource(ctx)
+		outputFile := mod.sourceProvider.generateSource(ctx, deps)
 		mod.outputFile = android.OptionalPathForPath(outputFile)
 		mod.subName = ctx.ModuleSubDir()
 	}
@@ -849,6 +854,11 @@
 				depFlag = "-lstatic=" + libName
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				depPaths.depFlags = append(depPaths.depFlags, depFlag)
+				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.coverageFiles = append(depPaths.coverageFiles, ccDep.CoverageFiles()...)
 				directStaticLibDeps = append(directStaticLibDeps, ccDep)
 				mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
@@ -856,6 +866,11 @@
 				depFlag = "-ldylib=" + libName
 				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
 				depPaths.depFlags = append(depPaths.depFlags, depFlag)
+				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()...)
+				}
 				directSharedLibDeps = append(directSharedLibDeps, ccDep)
 				mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
 				exportDep = true
@@ -916,6 +931,9 @@
 	// Dedup exported flags from dependencies
 	depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
 	depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
+	depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
+	depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
+	depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths)
 
 	return depPaths
 }
diff --git a/rust/source_provider.go b/rust/source_provider.go
index e034d2c..da6147a 100644
--- a/rust/source_provider.go
+++ b/rust/source_provider.go
@@ -33,7 +33,7 @@
 var _ SourceProvider = (*baseSourceProvider)(nil)
 
 type SourceProvider interface {
-	generateSource(ctx android.ModuleContext) android.Path
+	generateSource(ctx android.ModuleContext, deps PathDeps) android.Path
 	Srcs() android.Paths
 	sourceProviderProps() []interface{}
 	sourceProviderDeps(ctx DepsContext, deps Deps) Deps
@@ -43,7 +43,7 @@
 	return android.Paths{sp.outputFile}
 }
 
-func (sp *baseSourceProvider) generateSource(ctx android.ModuleContext) android.Path {
+func (sp *baseSourceProvider) generateSource(ctx android.ModuleContext, deps PathDeps) android.Path {
 	panic("baseSourceProviderModule does not implement generateSource()")
 }
 
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index a2198e9..931ca3c 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -204,8 +204,8 @@
 		}
 	`)
 
-	sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output
-	sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output
+	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")
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 3e76008..7591020 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -406,13 +406,17 @@
 // Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its
 // descendants
 func sdkDepsMutator(mctx android.TopDownMutatorContext) {
-	if m, ok := mctx.Module().(android.SdkAware); ok {
+	if parent, ok := mctx.Module().(interface {
+		android.DepIsInSameApex
+		android.RequiredSdks
+	}); ok {
 		// Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks()
 		// by reading its own properties like `uses_sdks`.
-		requiredSdks := m.RequiredSdks()
+		requiredSdks := parent.RequiredSdks()
 		if len(requiredSdks) > 0 {
 			mctx.VisitDirectDeps(func(m android.Module) {
-				if dep, ok := m.(android.SdkAware); ok {
+				// Only propagate required sdks from the apex onto its contents.
+				if dep, ok := m.(android.SdkAware); ok && parent.DepIsInSameApex(mctx, dep) {
 					dep.BuildWithSdks(requiredSdks)
 				}
 			})
@@ -423,15 +427,28 @@
 // Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the
 // versioned module is used instead of the un-versioned (in-development) module libfoo
 func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
-		if sdk := m.ContainingSdk(); !sdk.Unversioned() {
-			if m.RequiredSdks().Contains(sdk) {
-				// Note that this replacement is done only for the modules that have the same
-				// variations as the current module. Since current module is already mutated for
-				// apex references in other APEXes are not affected by this replacement.
-				memberName := m.MemberName()
-				mctx.ReplaceDependencies(memberName)
-			}
+	if versionedSdkMember, ok := mctx.Module().(android.SdkAware); ok && versionedSdkMember.IsInAnySdk() {
+		if sdk := versionedSdkMember.ContainingSdk(); !sdk.Unversioned() {
+			// Only replace dependencies to <sdkmember> with <sdkmember@required-version>
+			// if the depending module requires it. e.g.
+			//      foo -> sdkmember
+			// will be transformed to:
+			//      foo -> sdkmember@1
+			// if and only if foo is a member of an APEX that requires version 1 of the
+			// sdk containing sdkmember.
+			memberName := versionedSdkMember.MemberName()
+
+			// Replace dependencies on sdkmember with a dependency on the current module which
+			// is a versioned prebuilt of the sdkmember if required.
+			mctx.ReplaceDependenciesIf(memberName, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
+				// from - foo
+				// to - sdkmember
+				replace := false
+				if parent, ok := from.(android.RequiredSdks); ok {
+					replace = parent.RequiredSdks().Contains(sdk)
+				}
+				return replace
+			})
 		}
 	}
 }
diff --git a/third_party/zip/zip_test.go b/third_party/zip/zip_test.go
index 7373660..559c914 100644
--- a/third_party/zip/zip_test.go
+++ b/third_party/zip/zip_test.go
@@ -219,7 +219,7 @@
 	}
 }
 
-// fakeHash32 is a dummy Hash32 that always returns 0.
+// fakeHash32 is a fake Hash32 that always returns 0.
 type fakeHash32 struct {
 	hash.Hash32
 }
diff --git a/ui/build/config.go b/ui/build/config.go
index ba477e6..3fa0479 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -96,7 +96,7 @@
 		environ: OsEnvironment(),
 	}
 
-	// Sane default matching ninja
+	// Default matching ninja
 	ret.parallel = runtime.NumCPU() + 2
 	ret.keepGoing = 1
 
diff --git a/ui/build/upload.go b/ui/build/upload.go
index 1cc2e94..a9346e0 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -44,7 +44,7 @@
 // environment variable. The metrics files are copied to a temporary directory
 // and the uploader is then executed in the background to allow the user to continue
 // working.
-func UploadMetrics(ctx Context, config Config, forceDumbOutput bool, buildStarted time.Time, files ...string) {
+func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, files ...string) {
 	ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
 	defer ctx.EndTrace()
 
@@ -105,7 +105,7 @@
 	// Start the uploader in the background as it takes several milliseconds to start the uploader
 	// and prepare the metrics for upload. This affects small commands like "lunch".
 	cmd := Command(ctx, config, "upload metrics", uploader, "--upload-metrics", pbFile)
-	if forceDumbOutput {
+	if simpleOutput {
 		cmd.RunOrFatal()
 	} else {
 		cmd.RunAndStreamOrFatal()
diff --git a/ui/terminal/Android.bp b/ui/terminal/Android.bp
index b533b0d..aa6e35d 100644
--- a/ui/terminal/Android.bp
+++ b/ui/terminal/Android.bp
@@ -17,7 +17,7 @@
     pkgPath: "android/soong/ui/terminal",
     deps: ["soong-ui-status"],
     srcs: [
-        "dumb_status.go",
+        "simple_status.go",
         "format.go",
         "smart_status.go",
         "status.go",
diff --git a/ui/terminal/dumb_status.go b/ui/terminal/simple_status.go
similarity index 70%
rename from ui/terminal/dumb_status.go
rename to ui/terminal/simple_status.go
index 201770f..4e8c568 100644
--- a/ui/terminal/dumb_status.go
+++ b/ui/terminal/simple_status.go
@@ -21,31 +21,31 @@
 	"android/soong/ui/status"
 )
 
-type dumbStatusOutput struct {
+type simpleStatusOutput struct {
 	writer    io.Writer
 	formatter formatter
 }
 
-// NewDumbStatusOutput returns a StatusOutput that represents the
+// NewSimpleStatusOutput returns a StatusOutput that represents the
 // current build status similarly to Ninja's built-in terminal
 // output.
-func NewDumbStatusOutput(w io.Writer, formatter formatter) status.StatusOutput {
-	return &dumbStatusOutput{
+func NewSimpleStatusOutput(w io.Writer, formatter formatter) status.StatusOutput {
+	return &simpleStatusOutput{
 		writer:    w,
 		formatter: formatter,
 	}
 }
 
-func (s *dumbStatusOutput) Message(level status.MsgLevel, message string) {
+func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) {
 	if level >= status.StatusLvl {
 		fmt.Fprintln(s.writer, s.formatter.message(level, message))
 	}
 }
 
-func (s *dumbStatusOutput) StartAction(action *status.Action, counts status.Counts) {
+func (s *simpleStatusOutput) StartAction(action *status.Action, counts status.Counts) {
 }
 
-func (s *dumbStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
+func (s *simpleStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
 	str := result.Description
 	if str == "" {
 		str = result.Command
@@ -63,9 +63,9 @@
 	}
 }
 
-func (s *dumbStatusOutput) Flush() {}
+func (s *simpleStatusOutput) Flush() {}
 
-func (s *dumbStatusOutput) Write(p []byte) (int, error) {
+func (s *simpleStatusOutput) Write(p []byte) (int, error) {
 	fmt.Fprint(s.writer, string(p))
 	return len(p), nil
 }
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index 60dfc70..d8e7392 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -26,12 +26,12 @@
 //
 // statusFormat takes nearly all the same options as NINJA_STATUS.
 // %c is currently unsupported.
-func NewStatusOutput(w io.Writer, statusFormat string, forceDumbOutput, quietBuild bool) status.StatusOutput {
+func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild bool) status.StatusOutput {
 	formatter := newFormatter(statusFormat, quietBuild)
 
-	if !forceDumbOutput && isSmartTerminal(w) {
+	if !forceSimpleOutput && isSmartTerminal(w) {
 		return NewSmartStatusOutput(w, formatter)
 	} else {
-		return NewDumbStatusOutput(w, formatter)
+		return NewSimpleStatusOutput(w, formatter)
 	}
 }
diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go
index 9f60829..aa69dff 100644
--- a/ui/terminal/status_test.go
+++ b/ui/terminal/status_test.go
@@ -26,64 +26,64 @@
 
 func TestStatusOutput(t *testing.T) {
 	tests := []struct {
-		name  string
-		calls func(stat status.StatusOutput)
-		smart string
-		dumb  string
+		name   string
+		calls  func(stat status.StatusOutput)
+		smart  string
+		simple string
 	}{
 		{
-			name:  "two actions",
-			calls: twoActions,
-			smart: "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
-			dumb:  "[ 50% 1/2] action1\n[100% 2/2] action2\n",
+			name:   "two actions",
+			calls:  twoActions,
+			smart:  "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+			simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
 		},
 		{
-			name:  "two parallel actions",
-			calls: twoParallelActions,
-			smart: "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[  0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
-			dumb:  "[ 50% 1/2] action1\n[100% 2/2] action2\n",
+			name:   "two parallel actions",
+			calls:  twoParallelActions,
+			smart:  "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[  0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+			simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
 		},
 		{
-			name:  "action with output",
-			calls: actionsWithOutput,
-			smart: "\r\x1b[1m[  0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
-			dumb:  "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
+			name:   "action with output",
+			calls:  actionsWithOutput,
+			smart:  "\r\x1b[1m[  0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+			simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
 		},
 		{
-			name:  "action with output without newline",
-			calls: actionsWithOutputWithoutNewline,
-			smart: "\r\x1b[1m[  0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
-			dumb:  "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
+			name:   "action with output without newline",
+			calls:  actionsWithOutputWithoutNewline,
+			smart:  "\r\x1b[1m[  0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+			simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
 		},
 		{
-			name:  "action with error",
-			calls: actionsWithError,
-			smart: "\r\x1b[1m[  0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
-			dumb:  "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n",
+			name:   "action with error",
+			calls:  actionsWithError,
+			smart:  "\r\x1b[1m[  0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+			simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n",
 		},
 		{
-			name:  "action with empty description",
-			calls: actionWithEmptyDescription,
-			smart: "\r\x1b[1m[  0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n",
-			dumb:  "[100% 1/1] command1\n",
+			name:   "action with empty description",
+			calls:  actionWithEmptyDescription,
+			smart:  "\r\x1b[1m[  0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n",
+			simple: "[100% 1/1] command1\n",
 		},
 		{
-			name:  "messages",
-			calls: actionsWithMessages,
-			smart: "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
-			dumb:  "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n",
+			name:   "messages",
+			calls:  actionsWithMessages,
+			smart:  "\r\x1b[1m[  0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+			simple: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n",
 		},
 		{
-			name:  "action with long description",
-			calls: actionWithLongDescription,
-			smart: "\r\x1b[1m[  0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n",
-			dumb:  "[ 50% 1/2] action with very long description to test eliding\n",
+			name:   "action with long description",
+			calls:  actionWithLongDescription,
+			smart:  "\r\x1b[1m[  0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n",
+			simple: "[ 50% 1/2] action with very long description to test eliding\n",
 		},
 		{
-			name:  "action with output with ansi codes",
-			calls: actionWithOuptutWithAnsiCodes,
-			smart: "\r\x1b[1m[  0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n",
-			dumb:  "[100% 1/1] action1\ncolor\n",
+			name:   "action with output with ansi codes",
+			calls:  actionWithOuptutWithAnsiCodes,
+			smart:  "\r\x1b[1m[  0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n",
+			simple: "[100% 1/1] action1\ncolor\n",
 		},
 	}
 
@@ -103,24 +103,24 @@
 				}
 			})
 
-			t.Run("dumb", func(t *testing.T) {
-				dumb := &bytes.Buffer{}
-				stat := NewStatusOutput(dumb, "", false, false)
+			t.Run("simple", func(t *testing.T) {
+				simple := &bytes.Buffer{}
+				stat := NewStatusOutput(simple, "", false, false)
 				tt.calls(stat)
 				stat.Flush()
 
-				if g, w := dumb.String(), tt.dumb; g != w {
+				if g, w := simple.String(), tt.simple; g != w {
 					t.Errorf("want:\n%q\ngot:\n%q", w, g)
 				}
 			})
 
-			t.Run("force dumb", func(t *testing.T) {
+			t.Run("force simple", func(t *testing.T) {
 				smart := &fakeSmartTerminal{termWidth: 40}
 				stat := NewStatusOutput(smart, "", true, false)
 				tt.calls(stat)
 				stat.Flush()
 
-				if g, w := smart.String(), tt.dumb; g != w {
+				if g, w := smart.String(), tt.simple; g != w {
 					t.Errorf("want:\n%q\ngot:\n%q", w, g)
 				}
 			})