Merge "[trivial] Remove dead code"
diff --git a/README.md b/README.md
index ebbe8bc..531ef4c 100644
--- a/README.md
+++ b/README.md
@@ -337,6 +337,19 @@
 This will bind mount the Soong source directories into the directory in the layout expected by
 the IDE.
 
+### Running Soong in a debugger
+
+To run the soong_build process in a debugger, install `dlv` and then start the build with
+`SOONG_DELVE=<listen addr>` in the environment.
+For examle:
+```bash
+SOONG_DELVE=:1234 m nothing
+```
+and then in another terminal:
+```
+dlv connect :1234
+```
+
 ## Contact
 
 Email android-building@googlegroups.com (external) for any questions, or see
diff --git a/android/env.go b/android/env.go
index 469dfff..d9f2db2 100644
--- a/android/env.go
+++ b/android/env.go
@@ -16,6 +16,7 @@
 
 import (
 	"os"
+	"os/exec"
 	"strings"
 
 	"android/soong/env"
@@ -29,8 +30,16 @@
 // a manifest regeneration.
 
 var originalEnv map[string]string
+var SoongDelveListen string
+var SoongDelvePath string
 
 func init() {
+	// Delve support needs to read this environment variable very early, before NewConfig has created a way to
+	// access originalEnv with dependencies.  Store the value where soong_build can find it, it will manually
+	// ensure the dependencies are created.
+	SoongDelveListen = os.Getenv("SOONG_DELVE")
+	SoongDelvePath, _ = exec.LookPath("dlv")
+
 	originalEnv = make(map[string]string)
 	for _, env := range os.Environ() {
 		idx := strings.IndexRune(env, '=')
@@ -38,6 +47,8 @@
 			originalEnv[env[:idx]] = env[idx+1:]
 		}
 	}
+	// Clear the environment to prevent use of os.Getenv(), which would not provide dependencies on environment
+	// variable values.  The environment is available through ctx.Config().Getenv, ctx.Config().IsEnvTrue, etc.
 	os.Clearenv()
 }
 
diff --git a/android/hooks.go b/android/hooks.go
index 2d2f797..5810996 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -129,6 +129,8 @@
 
 func LoadHookMutator(ctx TopDownMutatorContext) {
 	if m, ok := ctx.Module().(Module); ok {
+		m.base().commonProperties.DebugName = ctx.ModuleName()
+
 		// Cast through *topDownMutatorContext because AppendProperties is implemented
 		// on *topDownMutatorContext but not exposed through TopDownMutatorContext
 		var loadHookCtx LoadHookContext = ctx.(*topDownMutatorContext)
diff --git a/android/module.go b/android/module.go
index 43b8763..2d4c1b5 100644
--- a/android/module.go
+++ b/android/module.go
@@ -203,6 +203,9 @@
 	RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
 	VariablesForTests() map[string]string
 
+	// String returns a string that includes the module name and variants for printing during debugging.
+	String() string
+
 	// Get the qualified module id for this module.
 	qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName
 
@@ -408,6 +411,11 @@
 	NamespaceExportedToMake bool `blueprint:"mutated"`
 
 	MissingDeps []string `blueprint:"mutated"`
+
+	// Name and variant strings stored by mutators to enable Module.String()
+	DebugName       string   `blueprint:"mutated"`
+	DebugMutators   []string `blueprint:"mutated"`
+	DebugVariations []string `blueprint:"mutated"`
 }
 
 type hostAndDeviceProperties struct {
@@ -625,6 +633,23 @@
 	return String(m.nameProperties.Name)
 }
 
+// String returns a string that includes the module name and variants for printing during debugging.
+func (m *ModuleBase) String() string {
+	sb := strings.Builder{}
+	sb.WriteString(m.commonProperties.DebugName)
+	sb.WriteString("{")
+	for i := range m.commonProperties.DebugMutators {
+		if i != 0 {
+			sb.WriteString(",")
+		}
+		sb.WriteString(m.commonProperties.DebugMutators[i])
+		sb.WriteString(":")
+		sb.WriteString(m.commonProperties.DebugVariations[i])
+	}
+	sb.WriteString("}")
+	return sb.String()
+}
+
 // BaseModuleName returns the name of the module as specified in the blueprints file.
 func (m *ModuleBase) BaseModuleName() string {
 	return String(m.nameProperties.Name)
diff --git a/android/mutator.go b/android/mutator.go
index 070b420..b799432 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -117,6 +117,8 @@
 type TopDownMutatorContext interface {
 	BaseModuleContext
 
+	MutatorName() string
+
 	Rename(name string)
 
 	CreateModule(blueprint.ModuleFactory, ...interface{})
@@ -132,6 +134,8 @@
 type BottomUpMutatorContext interface {
 	BaseModuleContext
 
+	MutatorName() string
+
 	Rename(name string)
 
 	AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string)
@@ -229,16 +233,26 @@
 // non-overridden method has to be forwarded.  There are fewer non-overridden methods, so use the latter.  The following
 // methods forward to the identical blueprint versions for topDownMutatorContext and bottomUpMutatorContext.
 
+func (t *topDownMutatorContext) MutatorName() string {
+	return t.bp.MutatorName()
+}
+
 func (t *topDownMutatorContext) Rename(name string) {
 	t.bp.Rename(name)
+	t.Module().base().commonProperties.DebugName = name
 }
 
 func (t *topDownMutatorContext) CreateModule(factory blueprint.ModuleFactory, props ...interface{}) {
 	t.bp.CreateModule(factory, props...)
 }
 
+func (b *bottomUpMutatorContext) MutatorName() string {
+	return b.bp.MutatorName()
+}
+
 func (b *bottomUpMutatorContext) Rename(name string) {
 	b.bp.Rename(name)
+	b.Module().base().commonProperties.DebugName = name
 }
 
 func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) {
@@ -250,11 +264,27 @@
 }
 
 func (b *bottomUpMutatorContext) CreateVariations(variations ...string) []blueprint.Module {
-	return b.bp.CreateVariations(variations...)
+	modules := b.bp.CreateVariations(variations...)
+
+	for i := range variations {
+		base := modules[i].(Module).base()
+		base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
+		base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
+	}
+
+	return modules
 }
 
 func (b *bottomUpMutatorContext) CreateLocalVariations(variations ...string) []blueprint.Module {
-	return b.bp.CreateLocalVariations(variations...)
+	modules := b.bp.CreateLocalVariations(variations...)
+
+	for i := range variations {
+		base := modules[i].(Module).base()
+		base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, b.MutatorName())
+		base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variations[i])
+	}
+
+	return modules
 }
 
 func (b *bottomUpMutatorContext) SetDependencyVariation(variation string) {
diff --git a/android/mutator_test.go b/android/mutator_test.go
index 4cef400..0b23434 100644
--- a/android/mutator_test.go
+++ b/android/mutator_test.go
@@ -15,8 +15,6 @@
 package android
 
 import (
-	"io/ioutil"
-	"os"
 	"reflect"
 	"testing"
 
@@ -26,6 +24,8 @@
 type mutatorTestModule struct {
 	ModuleBase
 	props struct {
+		Deps_missing_deps    []string
+		Mutator_missing_deps []string
 	}
 
 	missingDeps []string
@@ -48,20 +48,14 @@
 }
 
 func (m *mutatorTestModule) DepsMutator(ctx BottomUpMutatorContext) {
-	ctx.AddDependency(ctx.Module(), nil, "regular_missing_dep")
+	ctx.AddDependency(ctx.Module(), nil, m.props.Deps_missing_deps...)
 }
 
 func addMissingDependenciesMutator(ctx TopDownMutatorContext) {
-	ctx.AddMissingDependencies([]string{"added_missing_dep"})
+	ctx.AddMissingDependencies(ctx.Module().(*mutatorTestModule).props.Mutator_missing_deps)
 }
 
 func TestMutatorAddMissingDependencies(t *testing.T) {
-	buildDir, err := ioutil.TempDir("", "soong_mutator_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	config := TestConfig(buildDir, nil)
 	config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true)
 
@@ -76,6 +70,8 @@
 	bp := `
 		test {
 			name: "foo",
+			deps_missing_deps: ["regular_missing_dep"],
+			mutator_missing_deps: ["added_missing_dep"],
 		}
 	`
 
@@ -97,3 +93,107 @@
 		t.Errorf("want foo missing deps %q, got %q", w, g)
 	}
 }
+
+func TestModuleString(t *testing.T) {
+	ctx := NewTestContext()
+
+	var moduleStrings []string
+
+	ctx.PreArchMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("pre_arch", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.CreateVariations("a", "b")
+		})
+		ctx.TopDown("rename_top_down", func(ctx TopDownMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.Rename(ctx.Module().base().Name() + "_renamed1")
+		})
+	})
+
+	ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("pre_deps", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.CreateVariations("c", "d")
+		})
+	})
+
+	ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) {
+		ctx.BottomUp("post_deps", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.CreateLocalVariations("e", "f")
+		})
+		ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+			ctx.Rename(ctx.Module().base().Name() + "_renamed2")
+		})
+		ctx.BottomUp("final", func(ctx BottomUpMutatorContext) {
+			moduleStrings = append(moduleStrings, ctx.Module().String())
+		})
+	})
+
+	ctx.RegisterModuleType("test", ModuleFactoryAdaptor(mutatorTestModuleFactory))
+
+	bp := `
+		test {
+			name: "foo",
+		}
+	`
+
+	mockFS := map[string][]byte{
+		"Android.bp": []byte(bp),
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	ctx.Register()
+
+	config := TestConfig(buildDir, nil)
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	FailIfErrored(t, errs)
+
+	want := []string{
+		// Initial name.
+		"foo{}",
+
+		// After pre_arch (reversed because rename_top_down is TopDown so it visits in reverse order).
+		"foo{pre_arch:b}",
+		"foo{pre_arch:a}",
+
+		// After rename_top_down.
+		"foo_renamed1{pre_arch:a}",
+		"foo_renamed1{pre_arch:b}",
+
+		// After pre_deps.
+		"foo_renamed1{pre_arch:a,pre_deps:c}",
+		"foo_renamed1{pre_arch:a,pre_deps:d}",
+		"foo_renamed1{pre_arch:b,pre_deps:c}",
+		"foo_renamed1{pre_arch:b,pre_deps:d}",
+
+		// After post_deps.
+		"foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}",
+		"foo_renamed1{pre_arch:a,pre_deps:c,post_deps:f}",
+		"foo_renamed1{pre_arch:a,pre_deps:d,post_deps:e}",
+		"foo_renamed1{pre_arch:a,pre_deps:d,post_deps:f}",
+		"foo_renamed1{pre_arch:b,pre_deps:c,post_deps:e}",
+		"foo_renamed1{pre_arch:b,pre_deps:c,post_deps:f}",
+		"foo_renamed1{pre_arch:b,pre_deps:d,post_deps:e}",
+		"foo_renamed1{pre_arch:b,pre_deps:d,post_deps:f}",
+
+		// After rename_bottom_up.
+		"foo_renamed2{pre_arch:a,pre_deps:c,post_deps:e}",
+		"foo_renamed2{pre_arch:a,pre_deps:c,post_deps:f}",
+		"foo_renamed2{pre_arch:a,pre_deps:d,post_deps:e}",
+		"foo_renamed2{pre_arch:a,pre_deps:d,post_deps:f}",
+		"foo_renamed2{pre_arch:b,pre_deps:c,post_deps:e}",
+		"foo_renamed2{pre_arch:b,pre_deps:c,post_deps:f}",
+		"foo_renamed2{pre_arch:b,pre_deps:d,post_deps:e}",
+		"foo_renamed2{pre_arch:b,pre_deps:d,post_deps:f}",
+	}
+
+	if !reflect.DeepEqual(moduleStrings, want) {
+		t.Errorf("want module String() values:\n%q\ngot:\n%q", want, moduleStrings)
+	}
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index f35d1fe..1893e8b 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -31,61 +31,64 @@
 // work regardless of these restrictions.
 //
 // A module is disallowed if all of the following are true:
-// - it is in one of the "in" paths
-// - it is not in one of the "notIn" paths
-// - it has all "with" properties matched
+// - it is in one of the "In" paths
+// - it is not in one of the "NotIn" paths
+// - it has all "With" properties matched
 // - - values are matched in their entirety
 // - - nil is interpreted as an empty string
 // - - nested properties are separated with a '.'
 // - - if the property is a list, any of the values in the list being matches
 //     counts as a match
-// - it has none of the "without" properties matched (same rules as above)
+// - it has none of the "Without" properties matched (same rules as above)
 
 func registerNeverallowMutator(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("neverallow", neverallowMutator).Parallel()
 }
 
-var neverallows = createNeverAllows()
+var neverallows = []Rule{}
 
-func createNeverAllows() []*rule {
-	rules := []*rule{}
-	rules = append(rules, createTrebleRules()...)
-	rules = append(rules, createLibcoreRules()...)
-	rules = append(rules, createJavaDeviceForHostRules()...)
-	return rules
+func init() {
+	AddNeverAllowRules(createTrebleRules()...)
+	AddNeverAllowRules(createLibcoreRules()...)
+	AddNeverAllowRules(createJavaDeviceForHostRules()...)
 }
 
-func createTrebleRules() []*rule {
-	return []*rule{
-		neverallow().
-			in("vendor", "device").
-			with("vndk.enabled", "true").
-			without("vendor", "true").
-			because("the VNDK can never contain a library that is device dependent."),
-		neverallow().
-			with("vndk.enabled", "true").
-			without("vendor", "true").
-			without("owner", "").
-			because("a VNDK module can never have an owner."),
+// Add a NeverAllow rule to the set of rules to apply.
+func AddNeverAllowRules(rules ...Rule) {
+	neverallows = append(neverallows, rules...)
+}
+
+func createTrebleRules() []Rule {
+	return []Rule{
+		NeverAllow().
+			In("vendor", "device").
+			With("vndk.enabled", "true").
+			Without("vendor", "true").
+			Because("the VNDK can never contain a library that is device dependent."),
+		NeverAllow().
+			With("vndk.enabled", "true").
+			Without("vendor", "true").
+			Without("owner", "").
+			Because("a VNDK module can never have an owner."),
 
 		// TODO(b/67974785): always enforce the manifest
-		neverallow().
-			without("name", "libhidltransport").
-			with("product_variables.enforce_vintf_manifest.cflags", "*").
-			because("manifest enforcement should be independent of ."),
+		NeverAllow().
+			Without("name", "libhidltransport").
+			With("product_variables.enforce_vintf_manifest.cflags", "*").
+			Because("manifest enforcement should be independent of ."),
 
 		// TODO(b/67975799): vendor code should always use /vendor/bin/sh
-		neverallow().
-			without("name", "libc_bionic_ndk").
-			with("product_variables.treble_linker_namespaces.cflags", "*").
-			because("nothing should care if linker namespaces are enabled or not"),
+		NeverAllow().
+			Without("name", "libc_bionic_ndk").
+			With("product_variables.treble_linker_namespaces.cflags", "*").
+			Because("nothing should care if linker namespaces are enabled or not"),
 
 		// Example:
-		// *neverallow().with("Srcs", "main.cpp"))
+		// *NeverAllow().with("Srcs", "main.cpp"))
 	}
 }
 
-func createLibcoreRules() []*rule {
+func createLibcoreRules() []Rule {
 	var coreLibraryProjects = []string{
 		"libcore",
 		"external/apache-harmony",
@@ -102,27 +105,27 @@
 
 	// Core library constraints. The sdk_version: "none" can only be used in core library projects.
 	// Access to core library targets is restricted using visibility rules.
-	rules := []*rule{
-		neverallow().
-			notIn(coreLibraryProjects...).
-			with("sdk_version", "none"),
+	rules := []Rule{
+		NeverAllow().
+			NotIn(coreLibraryProjects...).
+			With("sdk_version", "none"),
 	}
 
 	return rules
 }
 
-func createJavaDeviceForHostRules() []*rule {
+func createJavaDeviceForHostRules() []Rule {
 	javaDeviceForHostProjectsWhitelist := []string{
 		"external/guava",
 		"external/robolectric-shadows",
 		"framework/layoutlib",
 	}
 
-	return []*rule{
-		neverallow().
-			notIn(javaDeviceForHostProjectsWhitelist...).
-			moduleType("java_device_for_host", "java_host_for_device").
-			because("java_device_for_host can only be used in whitelisted projects"),
+	return []Rule{
+		NeverAllow().
+			NotIn(javaDeviceForHostProjectsWhitelist...).
+			ModuleType("java_device_for_host", "java_host_for_device").
+			Because("java_device_for_host can only be used in whitelisted projects"),
 	}
 }
 
@@ -135,7 +138,8 @@
 	dir := ctx.ModuleDir() + "/"
 	properties := m.GetProperties()
 
-	for _, n := range neverallows {
+	for _, r := range neverallows {
+		n := r.(*rule)
 		if !n.appliesToPath(dir) {
 			continue
 		}
@@ -157,6 +161,23 @@
 	value  string   // e.x.: true
 }
 
+// A NeverAllow rule.
+type Rule interface {
+	In(path ...string) Rule
+
+	NotIn(path ...string) Rule
+
+	ModuleType(types ...string) Rule
+
+	NotModuleType(types ...string) Rule
+
+	With(properties, value string) Rule
+
+	Without(properties, value string) Rule
+
+	Because(reason string) Rule
+}
+
 type rule struct {
 	// User string for why this is a thing.
 	reason string
@@ -171,31 +192,32 @@
 	unlessProps []ruleProperty
 }
 
-func neverallow() *rule {
+// Create a new NeverAllow rule.
+func NeverAllow() Rule {
 	return &rule{}
 }
 
-func (r *rule) in(path ...string) *rule {
+func (r *rule) In(path ...string) Rule {
 	r.paths = append(r.paths, cleanPaths(path)...)
 	return r
 }
 
-func (r *rule) notIn(path ...string) *rule {
+func (r *rule) NotIn(path ...string) Rule {
 	r.unlessPaths = append(r.unlessPaths, cleanPaths(path)...)
 	return r
 }
 
-func (r *rule) moduleType(types ...string) *rule {
+func (r *rule) ModuleType(types ...string) Rule {
 	r.moduleTypes = append(r.moduleTypes, types...)
 	return r
 }
 
-func (r *rule) notModuleType(types ...string) *rule {
+func (r *rule) NotModuleType(types ...string) Rule {
 	r.unlessModuleTypes = append(r.unlessModuleTypes, types...)
 	return r
 }
 
-func (r *rule) with(properties, value string) *rule {
+func (r *rule) With(properties, value string) Rule {
 	r.props = append(r.props, ruleProperty{
 		fields: fieldNamesForProperties(properties),
 		value:  value,
@@ -203,7 +225,7 @@
 	return r
 }
 
-func (r *rule) without(properties, value string) *rule {
+func (r *rule) Without(properties, value string) Rule {
 	r.unlessProps = append(r.unlessProps, ruleProperty{
 		fields: fieldNamesForProperties(properties),
 		value:  value,
@@ -211,7 +233,7 @@
 	return r
 }
 
-func (r *rule) because(reason string) *rule {
+func (r *rule) Because(reason string) Rule {
 	r.reason = reason
 	return r
 }
diff --git a/android/notices.go b/android/notices.go
index dbb88fc..8503593 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -27,6 +27,13 @@
 	pctx.HostBinToolVariable("minigzip", "minigzip")
 }
 
+type NoticeOutputs struct {
+	Merged       OptionalPath
+	TxtOutput    OptionalPath
+	HtmlOutput   OptionalPath
+	HtmlGzOutput OptionalPath
+}
+
 var (
 	mergeNoticesRule = pctx.AndroidStaticRule("mergeNoticesRule", blueprint.RuleParams{
 		Command:     `${merge_notices} --output $out $in`,
@@ -35,13 +42,13 @@
 	})
 
 	generateNoticeRule = pctx.AndroidStaticRule("generateNoticeRule", blueprint.RuleParams{
-		Command: `rm -rf $tmpDir $$(dirname $out) && ` +
-			`mkdir -p $tmpDir $$(dirname $out) && ` +
-			`${generate_notice} --text-output $tmpDir/NOTICE.txt --html-output $tmpDir/NOTICE.html -t "$title" -s $inputDir && ` +
-			`${minigzip} -c $tmpDir/NOTICE.html > $out`,
+		Command: `rm -rf $$(dirname $txtOut) $$(dirname htmlOut) $$(dirname $out) && ` +
+			`mkdir -p $$(dirname $txtOut) $$(dirname htmlOut)  $$(dirname $out) && ` +
+			`${generate_notice} --text-output $txtOut --html-output $htmlOut -t "$title" -s $inputDir && ` +
+			`${minigzip} -c $htmlOut > $out`,
 		CommandDeps: []string{"${generate_notice}", "${minigzip}"},
 		Description: "produce notice file $out",
-	}, "tmpDir", "title", "inputDir")
+	}, "txtOut", "htmlOut", "title", "inputDir")
 )
 
 func MergeNotices(ctx ModuleContext, mergedNotice WritablePath, noticePaths []Path) {
@@ -54,7 +61,7 @@
 }
 
 func BuildNoticeOutput(ctx ModuleContext, installPath OutputPath, installFilename string,
-	noticePaths []Path) ModuleOutPath {
+	noticePaths []Path) NoticeOutputs {
 	// Merge all NOTICE files into one.
 	// TODO(jungjw): We should just produce a well-formatted NOTICE.html file in a single pass.
 	//
@@ -68,20 +75,28 @@
 	MergeNotices(ctx, mergedNotice, noticePaths)
 
 	// Transform the merged NOTICE file into a gzipped HTML file.
-	noticeOutput := PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
-	tmpDir := PathForModuleOut(ctx, "NOTICE_tmp")
+	txtOuptut := PathForModuleOut(ctx, "NOTICE_txt", "NOTICE.txt")
+	htmlOutput := PathForModuleOut(ctx, "NOTICE_html", "NOTICE.html")
+	htmlGzOutput := PathForModuleOut(ctx, "NOTICE", "NOTICE.html.gz")
 	title := "Notices for " + ctx.ModuleName()
 	ctx.Build(pctx, BuildParams{
-		Rule:        generateNoticeRule,
-		Description: "generate notice output",
-		Input:       mergedNotice,
-		Output:      noticeOutput,
+		Rule:            generateNoticeRule,
+		Description:     "generate notice output",
+		Input:           mergedNotice,
+		Output:          htmlGzOutput,
+		ImplicitOutputs: WritablePaths{txtOuptut, htmlOutput},
 		Args: map[string]string{
-			"tmpDir":   tmpDir.String(),
+			"txtOut":   txtOuptut.String(),
+			"htmlOut":  htmlOutput.String(),
 			"title":    title,
 			"inputDir": PathForModuleOut(ctx, "NOTICE_FILES/src").String(),
 		},
 	})
 
-	return noticeOutput
+	return NoticeOutputs{
+		Merged:       OptionalPathForPath(mergedNotice),
+		TxtOutput:    OptionalPathForPath(txtOuptut),
+		HtmlOutput:   OptionalPathForPath(htmlOutput),
+		HtmlGzOutput: OptionalPathForPath(htmlGzOutput),
+	}
 }
diff --git a/android/package_test.go b/android/package_test.go
index f1f47ac..e5b0556 100644
--- a/android/package_test.go
+++ b/android/package_test.go
@@ -1,8 +1,6 @@
 package android
 
 import (
-	"io/ioutil"
-	"os"
 	"testing"
 )
 
@@ -58,15 +56,9 @@
 }
 
 func TestPackage(t *testing.T) {
-	buildDir, err := ioutil.TempDir("", "soong_package_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	for _, test := range packageTests {
 		t.Run(test.name, func(t *testing.T) {
-			_, errs := testPackage(buildDir, test.fs)
+			_, errs := testPackage(test.fs)
 
 			expectedErrors := test.expectedErrors
 			if expectedErrors == nil {
@@ -89,7 +81,7 @@
 	}
 }
 
-func testPackage(buildDir string, fs map[string][]byte) (*TestContext, []error) {
+func testPackage(fs map[string][]byte) (*TestContext, []error) {
 
 	// Create a new config per test as visibility information is stored in the config.
 	config := TestArchConfig(buildDir, nil)
diff --git a/android/path_properties_test.go b/android/path_properties_test.go
index fa187fa..e98c136 100644
--- a/android/path_properties_test.go
+++ b/android/path_properties_test.go
@@ -15,8 +15,6 @@
 package android
 
 import (
-	"io/ioutil"
-	"os"
 	"reflect"
 	"testing"
 )
@@ -85,12 +83,6 @@
 		},
 	}
 
-	buildDir, err := ioutil.TempDir("", "soong_path_properties_test")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(buildDir)
-
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			config := TestArchConfig(buildDir, nil)
diff --git a/apex/apex.go b/apex/apex.go
index a77e295..f683f96 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -108,6 +108,7 @@
 	executableTag  = dependencyTag{name: "executable"}
 	javaLibTag     = dependencyTag{name: "javaLib"}
 	prebuiltTag    = dependencyTag{name: "prebuilt"}
+	testTag        = dependencyTag{name: "test"}
 	keyTag         = dependencyTag{name: "key"}
 	certificateTag = dependencyTag{name: "certificate"}
 )
@@ -192,6 +193,8 @@
 	Native_shared_libs []string
 	// List of native executables
 	Binaries []string
+	// List of native tests
+	Tests []string
 }
 type apexMultilibProperties struct {
 	// Native dependencies whose compile_multilib is "first"
@@ -232,7 +235,7 @@
 	// List of native shared libs that are embedded inside this APEX bundle
 	Native_shared_libs []string
 
-	// List of native executables that are embedded inside this APEX bundle
+	// List of executables that are embedded inside this APEX bundle
 	Binaries []string
 
 	// List of java libraries that are embedded inside this APEX bundle
@@ -241,6 +244,9 @@
 	// List of prebuilt files that are embedded inside this APEX bundle
 	Prebuilts []string
 
+	// List of tests that are embedded inside this APEX bundle
+	Tests []string
+
 	// Name of the apex_key module that provides the private key to sign APEX
 	Key *string
 
@@ -299,6 +305,7 @@
 	pyBinary
 	goBinary
 	javaSharedLib
+	nativeTest
 )
 
 type apexPackaging int
@@ -361,6 +368,8 @@
 		return "EXECUTABLES"
 	case javaSharedLib:
 		return "JAVA_LIBRARIES"
+	case nativeTest:
+		return "NATIVE_TESTS"
 	default:
 		panic(fmt.Errorf("unkonwn class %d", class))
 	}
@@ -406,7 +415,8 @@
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
-	native_shared_libs []string, binaries []string, arch string, imageVariation string) {
+	native_shared_libs []string, binaries []string, tests []string,
+	arch string, imageVariation string) {
 	// Use *FarVariation* to be able to depend on modules having
 	// conflicting variations with this module. This is required since
 	// arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64'
@@ -422,6 +432,11 @@
 		{Mutator: "arch", Variation: arch},
 		{Mutator: "image", Variation: imageVariation},
 	}, executableTag, binaries...)
+
+	ctx.AddFarVariationDependencies([]blueprint.Variation{
+		{Mutator: "arch", Variation: arch},
+		{Mutator: "image", Variation: imageVariation},
+	}, testTag, tests...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -459,10 +474,19 @@
 			{Mutator: "link", Variation: "shared"},
 		}, sharedLibTag, a.properties.Native_shared_libs...)
 
+		// When multilib.* is omitted for tests, it implies
+		// multilib.both.
+		ctx.AddFarVariationDependencies([]blueprint.Variation{
+			{Mutator: "arch", Variation: target.String()},
+			{Mutator: "image", Variation: a.getImageVariation(config)},
+		}, testTag, a.properties.Tests...)
+
 		// Add native modules targetting both ABIs
 		addDependenciesForNativeModules(ctx,
 			a.properties.Multilib.Both.Native_shared_libs,
-			a.properties.Multilib.Both.Binaries, target.String(),
+			a.properties.Multilib.Both.Binaries,
+			a.properties.Multilib.Both.Tests,
+			target.String(),
 			a.getImageVariation(config))
 
 		isPrimaryAbi := i == 0
@@ -477,7 +501,9 @@
 			// Add native modules targetting the first ABI
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.First.Native_shared_libs,
-				a.properties.Multilib.First.Binaries, target.String(),
+				a.properties.Multilib.First.Binaries,
+				a.properties.Multilib.First.Tests,
+				target.String(),
 				a.getImageVariation(config))
 
 			// When multilib.* is omitted for prebuilts, it implies multilib.first.
@@ -491,24 +517,32 @@
 			// Add native modules targetting 32-bit ABI
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.Lib32.Native_shared_libs,
-				a.properties.Multilib.Lib32.Binaries, target.String(),
+				a.properties.Multilib.Lib32.Binaries,
+				a.properties.Multilib.Lib32.Tests,
+				target.String(),
 				a.getImageVariation(config))
 
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.Prefer32.Native_shared_libs,
-				a.properties.Multilib.Prefer32.Binaries, target.String(),
+				a.properties.Multilib.Prefer32.Binaries,
+				a.properties.Multilib.Prefer32.Tests,
+				target.String(),
 				a.getImageVariation(config))
 		case "lib64":
 			// Add native modules targetting 64-bit ABI
 			addDependenciesForNativeModules(ctx,
 				a.properties.Multilib.Lib64.Native_shared_libs,
-				a.properties.Multilib.Lib64.Binaries, target.String(),
+				a.properties.Multilib.Lib64.Binaries,
+				a.properties.Multilib.Lib64.Tests,
+				target.String(),
 				a.getImageVariation(config))
 
 			if !has32BitTarget {
 				addDependenciesForNativeModules(ctx,
 					a.properties.Multilib.Prefer32.Native_shared_libs,
-					a.properties.Multilib.Prefer32.Binaries, target.String(),
+					a.properties.Multilib.Prefer32.Binaries,
+					a.properties.Multilib.Prefer32.Tests,
+					target.String(),
 					a.getImageVariation(config))
 			}
 
@@ -517,7 +551,7 @@
 					if sanitizer == "hwaddress" {
 						addDependenciesForNativeModules(ctx,
 							[]string{"libclang_rt.hwasan-aarch64-android"},
-							nil, target.String(), a.getImageVariation(config))
+							nil, nil, target.String(), a.getImageVariation(config))
 						break
 					}
 				}
@@ -686,6 +720,11 @@
 		return
 	}
 
+	if len(a.properties.Tests) > 0 && !a.testApex {
+		ctx.PropertyErrorf("tests", "property not allowed in apex module type")
+		return
+	}
+
 	handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
 
 	ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
@@ -747,6 +786,14 @@
 				} else {
 					ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
 				}
+			case testTag:
+				if cc, ok := child.(*cc.Module); ok {
+					fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
+					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeTest, cc, nil})
+					return true
+				} else {
+					ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
+				}
 			case keyTag:
 				if key, ok := child.(*apexKey); ok {
 					a.private_key_file = key.private_key_file
@@ -858,8 +905,7 @@
 		return android.OptionalPath{}
 	}
 
-	return android.OptionalPathForPath(
-		android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles)))
+	return android.BuildNoticeOutput(ctx, a.installDir, apexFileName, android.FirstUniquePaths(noticeFiles)).HtmlGzOutput
 }
 
 func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType apexPackaging) {
@@ -916,7 +962,7 @@
 		var executablePaths []string // this also includes dirs
 		for _, f := range a.filesInfo {
 			pathInApex := filepath.Join(f.installDir, f.builtFile.Base())
-			if f.installDir == "bin" {
+			if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
 				executablePaths = append(executablePaths, pathInApex)
 				for _, s := range f.symlinks {
 					executablePaths = append(executablePaths, filepath.Join("bin", s))
@@ -1253,11 +1299,11 @@
 }
 
 func testApexBundleFactory() android.Module {
-	return ApexBundleFactory( /*testApex*/ true)
+	return ApexBundleFactory(true /*testApex*/)
 }
 
 func apexBundleFactory() android.Module {
-	return ApexBundleFactory( /*testApex*/ false)
+	return ApexBundleFactory(false /*testApex*/)
 }
 
 func ApexBundleFactory(testApex bool) android.Module {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 2e44db7..b410425 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -57,6 +57,7 @@
 	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(cc.LibraryHeaderFactory))
 	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(cc.BinaryFactory))
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+	ctx.RegisterModuleType("cc_test", android.ModuleFactoryAdaptor(cc.TestFactory))
 	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
 	ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
@@ -168,6 +169,7 @@
 		"system/sepolicy/apex/myapex_keytest-file_contexts": nil,
 		"system/sepolicy/apex/otherapex-file_contexts":      nil,
 		"mylib.cpp":                            nil,
+		"mytest.cpp":                           nil,
 		"myprebuilt":                           nil,
 		"my_include":                           nil,
 		"vendor/foo/devkeys/test.x509.pem":     nil,
@@ -1285,6 +1287,40 @@
 	}
 }
 
+func TestApexWithTests(t *testing.T) {
+	ctx := testApex(t, `
+		apex_test {
+			name: "myapex",
+			key: "myapex.key",
+			tests: [
+				"mytest",
+			],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_test {
+			name: "mytest",
+			gtest: false,
+			srcs: ["mytest.cpp"],
+			relative_install_path: "test",
+			system_shared_libs: [],
+			static_executable: true,
+			stl: "none",
+		}
+	`)
+
+	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+	copyCmds := apexRule.Args["copy_commands"]
+
+	// Ensure that test dep is copied into apex.
+	ensureContains(t, copyCmds, "image.apex/bin/test/mytest")
+}
+
 func TestMain(m *testing.M) {
 	run := func() int {
 		setUp()
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 41c7d46..30381e0 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -18,7 +18,12 @@
 	"flag"
 	"fmt"
 	"os"
+	"os/exec"
 	"path/filepath"
+	"strconv"
+	"strings"
+	"syscall"
+	"time"
 
 	"github.com/google/blueprint/bootstrap"
 
@@ -50,6 +55,42 @@
 }
 
 func main() {
+	if android.SoongDelveListen != "" {
+		if android.SoongDelvePath == "" {
+			fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv")
+			os.Exit(1)
+		}
+		pid := strconv.Itoa(os.Getpid())
+		cmd := []string{android.SoongDelvePath,
+			"attach", pid,
+			"--headless",
+			"-l", android.SoongDelveListen,
+			"--api-version=2",
+			"--accept-multiclient",
+			"--log",
+		}
+
+		fmt.Println("Starting", strings.Join(cmd, " "))
+		dlv := exec.Command(cmd[0], cmd[1:]...)
+		dlv.Stdout = os.Stdout
+		dlv.Stderr = os.Stderr
+		dlv.Stdin = nil
+
+		// Put dlv into its own process group so we can kill it and the child process it starts.
+		dlv.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
+
+		err := dlv.Start()
+		if err != nil {
+			// Print the error starting dlv and continue.
+			fmt.Println(err)
+		} else {
+			// Kill the process group for dlv when soong_build exits.
+			defer syscall.Kill(-dlv.Process.Pid, syscall.SIGKILL)
+			// Wait to give dlv a chance to connect and pause the process.
+			time.Sleep(time.Second)
+		}
+	}
+
 	flag.Parse()
 
 	// The top-level Blueprints file is passed as the first argument.
@@ -72,7 +113,17 @@
 
 	ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
 
-	bootstrap.Main(ctx.Context, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
+	extraNinjaDeps := []string{configuration.ConfigFileName, configuration.ProductVariablesFileName}
+
+	// Read the SOONG_DELVE again through configuration so that there is a dependency on the environment variable
+	// and soong_build will rerun when it is set for the first time.
+	if listen := configuration.Getenv("SOONG_DELVE"); listen != "" {
+		// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
+		// enabled even if it completed successfully.
+		extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.BuildDir(), "always_rerun_for_delve"))
+	}
+
+	bootstrap.Main(ctx.Context, configuration, extraNinjaDeps...)
 
 	if docFile != "" {
 		if err := writeDocs(ctx, docFile); err != nil {
diff --git a/java/androidmk.go b/java/androidmk.go
index 39c2d13..90fdd0f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -327,6 +327,18 @@
 					install := "$(LOCAL_MODULE_PATH)/" + strings.TrimSuffix(app.installApkName, ".apk") + split.suffix + ".apk"
 					fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED +=", split.path.String()+":"+install)
 				}
+				if app.noticeOutputs.Merged.Valid() {
+					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
+						app.installApkName, app.noticeOutputs.Merged.String(), app.installApkName+"_NOTICE")
+				}
+				if app.noticeOutputs.TxtOutput.Valid() {
+					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
+						app.installApkName, app.noticeOutputs.TxtOutput.String(), app.installApkName+"_NOTICE.txt")
+				}
+				if app.noticeOutputs.HtmlOutput.Valid() {
+					fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n",
+						app.installApkName, app.noticeOutputs.HtmlOutput.String(), app.installApkName+"_NOTICE.html")
+				}
 			},
 		},
 	}
diff --git a/java/app.go b/java/app.go
index f58b0f8..e12b56c 100644
--- a/java/app.go
+++ b/java/app.go
@@ -141,6 +141,8 @@
 	installApkName string
 
 	additionalAaptFlags []string
+
+	noticeOutputs android.NoticeOutputs
 }
 
 func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
@@ -357,11 +359,7 @@
 	return jniJarFile
 }
 
-func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext, installDir android.OutputPath) android.OptionalPath {
-	if !Bool(a.appProperties.Embed_notices) && !ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
-		return android.OptionalPath{}
-	}
-
+func (a *AndroidApp) noticeBuildActions(ctx android.ModuleContext, installDir android.OutputPath) {
 	// Collect NOTICE files from all dependencies.
 	seenModules := make(map[android.Module]bool)
 	noticePathSet := make(map[android.Path]bool)
@@ -391,7 +389,7 @@
 	}
 
 	if len(noticePathSet) == 0 {
-		return android.OptionalPath{}
+		return
 	}
 	var noticePaths []android.Path
 	for path := range noticePathSet {
@@ -400,9 +398,8 @@
 	sort.Slice(noticePaths, func(i, j int) bool {
 		return noticePaths[i].String() < noticePaths[j].String()
 	})
-	noticeFile := android.BuildNoticeOutput(ctx, installDir, a.installApkName+".apk", noticePaths)
 
-	return android.OptionalPathForPath(noticeFile)
+	a.noticeOutputs = android.BuildNoticeOutput(ctx, installDir, a.installApkName+".apk", noticePaths)
 }
 
 // Reads and prepends a main cert from the default cert dir if it hasn't been set already, i.e. it
@@ -455,7 +452,10 @@
 		installDir = android.PathForModuleInstall(ctx, "app", a.installApkName)
 	}
 
-	a.aapt.noticeFile = a.noticeBuildActions(ctx, installDir)
+	a.noticeBuildActions(ctx, installDir)
+	if Bool(a.appProperties.Embed_notices) || ctx.Config().IsEnvTrue("ALWAYS_EMBED_NOTICES") {
+		a.aapt.noticeFile = a.noticeOutputs.HtmlGzOutput
+	}
 
 	// Process all building blocks, from AAPT to certificates.
 	a.aaptBuildActions(ctx)
diff --git a/java/app_test.go b/java/app_test.go
index c7ea338..721dd4d 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1479,16 +1479,20 @@
 
 	// bar has NOTICE files to process, but embed_notices is not set.
 	bar := ctx.ModuleForTests("bar", "android_common")
-	mergeNotices = bar.MaybeRule("mergeNoticesRule")
-	if mergeNotices.Rule != nil {
-		t.Errorf("mergeNotices shouldn't have run for bar")
+	res = bar.Output("package-res.apk")
+	aapt2Flags = res.Args["flags"]
+	e = "-A " + buildDir + "/.intermediates/bar/android_common/NOTICE"
+	if strings.Contains(aapt2Flags, e) {
+		t.Errorf("bar shouldn't have the asset dir flag for NOTICE: %q", e)
 	}
 
 	// baz's embed_notice is true, but it doesn't have any NOTICE files.
 	baz := ctx.ModuleForTests("baz", "android_common")
-	mergeNotices = baz.MaybeRule("mergeNoticesRule")
-	if mergeNotices.Rule != nil {
-		t.Errorf("mergeNotices shouldn't have run for baz")
+	res = baz.Output("package-res.apk")
+	aapt2Flags = res.Args["flags"]
+	e = "-A " + buildDir + "/.intermediates/baz/android_common/NOTICE"
+	if strings.Contains(aapt2Flags, e) {
+		t.Errorf("baz shouldn't have the asset dir flag for NOTICE: %q", e)
 	}
 }
 
diff --git a/ui/build/config.go b/ui/build/config.go
index 4a70f06..4e19e9e 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -266,6 +266,10 @@
 	if err != nil {
 		ctx.Fatalf("Error retrieving top directory: %v", err)
 	}
+	dir, err = filepath.EvalSymlinks(dir)
+	if err != nil {
+		ctx.Fatalf("Unable to evaluate symlink of %s: %v", dir, err)
+	}
 	dir, err = filepath.Abs(dir)
 	if err != nil {
 		ctx.Fatalf("Unable to find absolute path %s: %v", dir, err)
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 856af11..7a1ee17 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -690,6 +690,9 @@
 	// Build files that exists in the source tree.
 	buildFiles []string
 
+	// Create root symlink that points to topDir.
+	rootSymlink bool
+
 	// ********* Action *********
 	// Arguments passed in to soong_ui.
 	args []string
@@ -738,6 +741,22 @@
 	createDirectories(t, topDir, tt.dirsInTrees)
 	createBuildFiles(t, topDir, tt.buildFiles)
 
+	if tt.rootSymlink {
+		// Create a secondary root source tree which points to the true root source tree.
+		symlinkTopDir, err := ioutil.TempDir("", "")
+		if err != nil {
+			t.Fatalf("failed to create symlink temp dir: %v", err)
+		}
+		defer os.RemoveAll(symlinkTopDir)
+
+		symlinkTopDir = filepath.Join(symlinkTopDir, "root")
+		err = os.Symlink(topDir, symlinkTopDir)
+		if err != nil {
+			t.Fatalf("failed to create symlink: %v", err)
+		}
+		topDir = symlinkTopDir
+	}
+
 	r := setTop(t, topDir)
 	defer r()
 
@@ -796,7 +815,17 @@
 		dirsInTrees:     []string{"0/1/2", "0/2", "0/3"},
 		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp"},
 		args:            []string{},
-		curDir:          "1/2/3/4/5/6/7/8/9",
+		curDir:          "0/2",
+		tidyOnly:        "",
+		expectedArgs:    []string{},
+		expectedEnvVars: []envVar{},
+	}, {
+		description:     "normal execution in symlink root source tree, no args",
+		dirsInTrees:     []string{"0/1/2", "0/2", "0/3"},
+		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp"},
+		rootSymlink:     true,
+		args:            []string{},
+		curDir:          "0/2",
 		tidyOnly:        "",
 		expectedArgs:    []string{},
 		expectedEnvVars: []envVar{},
@@ -932,6 +961,17 @@
 			description:     "build action executed at root directory",
 			dirsInTrees:     []string{},
 			buildFiles:      []string{},
+			rootSymlink:     false,
+			args:            []string{},
+			curDir:          ".",
+			tidyOnly:        "",
+			expectedArgs:    []string{},
+			expectedEnvVars: []envVar{},
+		}, {
+			description:     "build action executed at root directory in symlink",
+			dirsInTrees:     []string{},
+			buildFiles:      []string{},
+			rootSymlink:     true,
 			args:            []string{},
 			curDir:          ".",
 			tidyOnly:        "",
@@ -1080,6 +1120,20 @@
 		description:  "normal execution from top dir directory",
 		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
 		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/3/Android.bp", "0/2/Android.bp"},
+		rootSymlink:  false,
+		args:         []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
+		curDir:       ".",
+		tidyOnly:     "",
+		expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
+		expectedEnvVars: []envVar{
+			envVar{
+				name:  "ONE_SHOT_MAKEFILE",
+				value: ""}},
+	}, {
+		description:  "normal execution from top dir directory in symlink",
+		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
+		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/3/Android.bp", "0/2/Android.bp"},
+		rootSymlink:  true,
 		args:         []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
 		curDir:       ".",
 		tidyOnly:     "",
diff --git a/ui/build/exec.go b/ui/build/exec.go
index 5c312bc..e435c53 100644
--- a/ui/build/exec.go
+++ b/ui/build/exec.go
@@ -15,7 +15,10 @@
 package build
 
 import (
+	"bufio"
+	"io"
 	"os/exec"
+	"strings"
 )
 
 // Cmd is a wrapper of os/exec.Cmd that integrates with the build context for
@@ -139,3 +142,34 @@
 	st.Finish()
 	c.reportError(err)
 }
+
+// RunAndStreamOrFatal will run the command, while running print
+// any output, then handle any errors with a call to ctx.Fatal
+func (c *Cmd) RunAndStreamOrFatal() {
+	out, err := c.StdoutPipe()
+	if err != nil {
+		c.ctx.Fatal(err)
+	}
+	c.Stderr = c.Stdout
+
+	st := c.ctx.Status.StartTool()
+
+	c.StartOrFatal()
+
+	buf := bufio.NewReaderSize(out, 2*1024*1024)
+	for {
+		// Attempt to read whole lines, but write partial lines that are too long to fit in the buffer or hit EOF
+		line, err := buf.ReadString('\n')
+		if line != "" {
+			st.Print(strings.TrimSuffix(line, "\n"))
+		} else if err == io.EOF {
+			break
+		} else if err != nil {
+			c.ctx.Fatal(err)
+		}
+	}
+
+	err = c.Wait()
+	st.Finish()
+	c.reportError(err)
+}
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 7994f3a..b41ac20 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -103,7 +103,7 @@
 	}()
 
 	ctx.Status.Status("Starting ninja...")
-	cmd.RunAndPrintOrFatal()
+	cmd.RunAndStreamOrFatal()
 }
 
 type statusChecker struct {
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index e2c5043..a4be2ac 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -81,6 +81,7 @@
 	"bzip2":    Allowed,
 	"dd":       Allowed,
 	"diff":     Allowed,
+	"dlv":      Allowed,
 	"egrep":    Allowed,
 	"expr":     Allowed,
 	"find":     Allowed,
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index b94db74..11ff667 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -162,6 +162,10 @@
 		c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
 		c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())
 		sandboxArgs = append(sandboxArgs, "-N")
+	} else if dlv, _ := c.config.Environment().Get("SOONG_DELVE"); dlv != "" {
+		// The debugger is enabled and soong_build will pause until a remote delve process connects, allow
+		// network connections.
+		sandboxArgs = append(sandboxArgs, "-N")
 	}
 
 	// Stop nsjail from parsing arguments
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 2ce1ac9..3388417 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -120,7 +120,7 @@
 			"--frontend_file", fifo,
 			"-f", filepath.Join(config.SoongOutDir(), file))
 		cmd.Sandbox = soongSandbox
-		cmd.RunAndPrintOrFatal()
+		cmd.RunAndStreamOrFatal()
 	}
 
 	ninja("minibootstrap", ".minibootstrap/build.ninja")
diff --git a/ui/terminal/util.go b/ui/terminal/util.go
index f383ef1..7a603d7 100644
--- a/ui/terminal/util.go
+++ b/ui/terminal/util.go
@@ -23,10 +23,10 @@
 )
 
 func isSmartTerminal(w io.Writer) bool {
-	if term, ok := os.LookupEnv("TERM"); ok && term == "dumb" {
-		return false
-	}
 	if f, ok := w.(*os.File); ok {
+		if term, ok := os.LookupEnv("TERM"); ok && term == "dumb" {
+			return false
+		}
 		var termios syscall.Termios
 		_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, f.Fd(),
 			ioctlGetTermios, uintptr(unsafe.Pointer(&termios)),