Merge "Skip ABI checks for APEX variants of opt-in libraries"
diff --git a/android/mutator.go b/android/mutator.go
index b799432..82376e4 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -243,7 +243,8 @@
 }
 
 func (t *topDownMutatorContext) CreateModule(factory blueprint.ModuleFactory, props ...interface{}) {
-	t.bp.CreateModule(factory, props...)
+	common := []interface{}{&t.Module().base().commonProperties}
+	t.bp.CreateModule(factory, append(common, props...)...)
 }
 
 func (b *bottomUpMutatorContext) MutatorName() string {
diff --git a/android/prebuilt.go b/android/prebuilt.go
index b674153..8559df9 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -29,7 +29,7 @@
 	blueprint.BaseDependencyTag
 }
 
-var prebuiltDepTag prebuiltDependencyTag
+var PrebuiltDepTag prebuiltDependencyTag
 
 type PrebuiltProperties struct {
 	// When prefer is set to true the prebuilt will be used instead of any source module with
@@ -127,7 +127,7 @@
 		p := m.Prebuilt()
 		name := m.base().BaseModuleName()
 		if ctx.OtherModuleExists(name) {
-			ctx.AddReverseDependency(ctx.Module(), prebuiltDepTag, name)
+			ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
 			p.properties.SourceExists = true
 		} else {
 			ctx.Rename(name)
@@ -147,7 +147,7 @@
 			p.properties.UsePrebuilt = p.usePrebuilt(ctx, nil)
 		}
 	} else if s, ok := ctx.Module().(Module); ok {
-		ctx.VisitDirectDepsWithTag(prebuiltDepTag, func(m Module) {
+		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(m Module) {
 			p := m.(PrebuiltInterface).Prebuilt()
 			if p.usePrebuilt(ctx, s) {
 				p.properties.UsePrebuilt = true
diff --git a/android/util.go b/android/util.go
index 97bec10..e02cca1 100644
--- a/android/util.go
+++ b/android/util.go
@@ -199,6 +199,13 @@
 	return list[totalSkip:]
 }
 
+// SortedUniqueStrings returns what the name says
+func SortedUniqueStrings(list []string) []string {
+	unique := FirstUniqueStrings(list)
+	sort.Strings(unique)
+	return unique
+}
+
 // checkCalledFromInit panics if a Go package's init function is not on the
 // call stack.
 func checkCalledFromInit() {
diff --git a/android/variable.go b/android/variable.go
index e9379b7..bfff81c 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -59,17 +59,6 @@
 			Cflags []string
 		}
 
-		// Product_is_iot is true for Android Things devices.
-		Product_is_iot struct {
-			Cflags       []string
-			Enabled      bool
-			Exclude_srcs []string
-			Init_rc      []string
-			Shared_libs  []string
-			Srcs         []string
-			Static_libs  []string
-		}
-
 		// treble_linker_namespaces is true when the system/vendor linker namespace separation is
 		// enabled.
 		Treble_linker_namespaces struct {
@@ -262,8 +251,6 @@
 
 	Override_rs_driver *string `json:",omitempty"`
 
-	Product_is_iot *bool `json:",omitempty"`
-
 	Fuchsia *bool `json:",omitempty"`
 
 	DeviceKernelHeaders []string `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index 34e09c0..e4fad83 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -46,13 +46,21 @@
 		Description: "fs_config ${out}",
 	}, "ro_paths", "exec_paths")
 
+	injectApexDependency = pctx.StaticRule("injectApexDependency", blueprint.RuleParams{
+		Command: `rm -f $out && ${jsonmodify} $in ` +
+			`-a provideNativeLibs ${provideNativeLibs} ` +
+			`-a requireNativeLibs ${requireNativeLibs} -o $out`,
+		CommandDeps: []string{"${jsonmodify}"},
+		Description: "Inject dependency into ${out}",
+	}, "provideNativeLibs", "requireNativeLibs")
+
 	// TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
 	// against the binary policy using sefcontext_compiler -p <policy>.
 
 	// TODO(b/114327326): automate the generation of file_contexts
 	apexRule = pctx.StaticRule("apexRule", blueprint.RuleParams{
 		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
-			`(${copy_commands}) && ` +
+			`(. ${out}.copy_commands) && ` +
 			`APEXER_TOOL_PATH=${tool_path} ` +
 			`${apexer} --force --manifest ${manifest} ` +
 			`--file_contexts ${file_contexts} ` +
@@ -62,18 +70,22 @@
 		CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
 			"${mke2fs}", "${resize2fs}", "${sefcontext_compile}",
 			"${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
-		Description: "APEX ${image_dir} => ${out}",
+		Rspfile:        "${out}.copy_commands",
+		RspfileContent: "${copy_commands}",
+		Description:    "APEX ${image_dir} => ${out}",
 	}, "tool_path", "image_dir", "copy_commands", "manifest", "file_contexts", "canned_fs_config", "key", "opt_flags")
 
 	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
 		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
-			`(${copy_commands}) && ` +
+			`(. ${out}.copy_commands) && ` +
 			`APEXER_TOOL_PATH=${tool_path} ` +
 			`${apexer} --force --manifest ${manifest} ` +
 			`--payload_type zip ` +
 			`${image_dir} ${out} `,
-		CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
-		Description: "ZipAPEX ${image_dir} => ${out}",
+		CommandDeps:    []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
+		Rspfile:        "${out}.copy_commands",
+		RspfileContent: "${copy_commands}",
+		Description:    "ZipAPEX ${image_dir} => ${out}",
 	}, "tool_path", "image_dir", "copy_commands", "manifest")
 
 	apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
@@ -139,6 +151,7 @@
 	pctx.HostBinToolVariable("soong_zip", "soong_zip")
 	pctx.HostBinToolVariable("zip2zip", "zip2zip")
 	pctx.HostBinToolVariable("zipalign", "zipalign")
+	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
 
 	android.RegisterModuleType("apex", apexBundleFactory)
 	android.RegisterModuleType("apex_test", testApexBundleFactory)
@@ -354,7 +367,7 @@
 	case both:
 		panic(fmt.Errorf("must be either zip or image"))
 	default:
-		panic(fmt.Errorf("unkonwn APEX type %d", a))
+		panic(fmt.Errorf("unknown APEX type %d", a))
 	}
 }
 
@@ -367,7 +380,7 @@
 	case both:
 		panic(fmt.Errorf("must be either zip or image"))
 	default:
-		panic(fmt.Errorf("unkonwn APEX type %d", a))
+		panic(fmt.Errorf("unknown APEX type %d", a))
 	}
 }
 
@@ -384,7 +397,7 @@
 	case nativeTest:
 		return "NATIVE_TESTS"
 	default:
-		panic(fmt.Errorf("unkonwn class %d", class))
+		panic(fmt.Errorf("unknown class %d", class))
 	}
 }
 
@@ -410,6 +423,8 @@
 	outputFiles      map[apexPackaging]android.WritablePath
 	installDir       android.OutputPath
 
+	prebuiltFileToDelete string
+
 	public_key_file  android.Path
 	private_key_file android.Path
 
@@ -425,6 +440,9 @@
 	flattened bool
 
 	testApex bool
+
+	// intermediate path for apex_manifest.json
+	manifestOut android.WritablePath
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -749,6 +767,10 @@
 
 	handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
 
+	// native lib dependencies
+	var provideNativeLibs []string
+	var requireNativeLibs []string
+
 	// Check if "uses" requirements are met with dependent apexBundles
 	var providedNativeSharedLibs []string
 	useVendor := proptools.Bool(a.properties.Use_vendor)
@@ -781,6 +803,9 @@
 			switch depTag {
 			case sharedLibTag:
 				if cc, ok := child.(*cc.Module); ok {
+					if cc.HasStubsVariants() {
+						provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
+					}
 					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
 					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
 					return true
@@ -862,6 +887,12 @@
 				} else {
 					ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
 				}
+			case android.PrebuiltDepTag:
+				// If the prebuilt is force disabled, remember to delete the prebuilt file
+				// that might have been installed in the previous builds
+				if prebuilt, ok := child.(*Prebuilt); ok && prebuilt.isForceDisabled() {
+					a.prebuiltFileToDelete = prebuilt.InstallFilename()
+				}
 			}
 		} else {
 			// indirect dependencies
@@ -886,6 +917,7 @@
 							if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
 								a.externalDeps = append(a.externalDeps, cc.Name())
 							}
+							requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
 							// Don't track further
 							return false
 						}
@@ -946,6 +978,21 @@
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = filesInfo
 
+	a.manifestOut = android.PathForModuleOut(ctx, "apex_manifest.json")
+	// put dependency({provide|require}NativeLibs) in apex_manifest.json
+	manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
+	provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
+	requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   injectApexDependency,
+		Input:  manifestSrc,
+		Output: a.manifestOut,
+		Args: map[string]string{
+			"provideNativeLibs": strings.Join(provideNativeLibs, " "),
+			"requireNativeLibs": strings.Join(requireNativeLibs, " "),
+		},
+	})
+
 	if a.apexTypes.zip() {
 		a.buildUnflattenedApex(ctx, zipApex)
 	}
@@ -993,8 +1040,6 @@
 		a.container_private_key_file = key
 	}
 
-	manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-
 	var abis []string
 	for _, target := range ctx.MultiTargets() {
 		if len(target.Arch.Abi) > 0 {
@@ -1024,7 +1069,7 @@
 		}
 	}
 	implicitInputs := append(android.Paths(nil), filesToCopy...)
-	implicitInputs = append(implicitInputs, manifest)
+	implicitInputs = append(implicitInputs, a.manifestOut)
 
 	outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
 	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
@@ -1119,7 +1164,7 @@
 				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
 				"image_dir":        android.PathForModuleOut(ctx, "image"+suffix).String(),
 				"copy_commands":    strings.Join(copyCommands, " && "),
-				"manifest":         manifest.String(),
+				"manifest":         a.manifestOut.String(),
 				"file_contexts":    fileContexts.String(),
 				"canned_fs_config": cannedFsConfig.String(),
 				"key":              a.private_key_file.String(),
@@ -1157,7 +1202,7 @@
 				"tool_path":     outHostBinDir + ":" + prebuiltSdkToolsBinDir,
 				"image_dir":     android.PathForModuleOut(ctx, "image"+suffix).String(),
 				"copy_commands": strings.Join(copyCommands, " && "),
-				"manifest":      manifest.String(),
+				"manifest":      a.manifestOut.String(),
 			},
 		})
 	}
@@ -1188,16 +1233,7 @@
 	if a.installable() {
 		// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
 		// with other ordinary files.
-		manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-
-		// rename to apex_manifest.json
-		copiedManifest := android.PathForModuleOut(ctx, "apex_manifest.json")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   android.Cp,
-			Input:  manifest,
-			Output: copiedManifest,
-		})
-		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
 
 		// rename to apex_pubkey
 		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
@@ -1362,6 +1398,10 @@
 				if len(a.externalDeps) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.externalDeps, " "))
 				}
+				if a.prebuiltFileToDelete != "" {
+					fmt.Fprintln(w, "LOCAL_POST_INSTALL_CMD :=", "rm -rf "+
+						filepath.Join("$(OUT_DIR)", a.installDir.RelPathString(), a.prebuiltFileToDelete))
+				}
 				fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
 
 				if apexType == imageApex {
@@ -1481,6 +1521,10 @@
 	// to build the prebuilts themselves.
 	forceDisable = forceDisable || ctx.Config().UnbundledBuild()
 
+	// Force disable the prebuilts when coverage is enabled.
+	forceDisable = forceDisable || ctx.DeviceConfig().NativeCoverageEnabled()
+	forceDisable = forceDisable || ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
+
 	// b/137216042 don't use prebuilts when address sanitizer is on
 	forceDisable = forceDisable || android.InList("address", ctx.Config().SanitizeDevice()) ||
 		android.InList("hwaddress", ctx.Config().SanitizeDevice())
@@ -1517,6 +1561,10 @@
 	p.properties.Source = src
 }
 
+func (p *Prebuilt) isForceDisabled() bool {
+	return p.properties.ForceDisable
+}
+
 func (p *Prebuilt) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "":
diff --git a/apex/apex_test.go b/apex/apex_test.go
index cecdaaf..38d2bf2 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -270,6 +270,13 @@
 	}
 }
 
+func ensureListEmpty(t *testing.T, result []string) {
+	t.Helper()
+	if len(result) > 0 {
+		t.Errorf("%q is expected to be empty", result)
+	}
+}
+
 // Minimal test
 func TestBasicApex(t *testing.T) {
 	ctx, _ := testApex(t, `
@@ -1060,6 +1067,109 @@
 	ensureContains(t, cFlags, "-Imy_include")
 }
 
+func TestDependenciesInApexManifest(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex_nodep",
+			key: "myapex.key",
+			native_shared_libs: ["lib_nodep"],
+			compile_multilib: "both",
+			file_contexts: "myapex",
+		}
+
+		apex {
+			name: "myapex_dep",
+			key: "myapex.key",
+			native_shared_libs: ["lib_dep"],
+			compile_multilib: "both",
+			file_contexts: "myapex",
+		}
+
+		apex {
+			name: "myapex_provider",
+			key: "myapex.key",
+			native_shared_libs: ["libfoo"],
+			compile_multilib: "both",
+			file_contexts: "myapex",
+		}
+
+		apex {
+			name: "myapex_selfcontained",
+			key: "myapex.key",
+			native_shared_libs: ["lib_dep", "libfoo"],
+			compile_multilib: "both",
+			file_contexts: "myapex",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "lib_nodep",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "lib_dep",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libfoo"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+
+		cc_library {
+			name: "libfoo",
+			srcs: ["mytest.cpp"],
+			stubs: {
+				versions: ["1"],
+			},
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	names := func(s string) (ns []string) {
+		for _, n := range strings.Split(s, " ") {
+			if len(n) > 0 {
+				ns = append(ns, n)
+			}
+		}
+		return
+	}
+
+	var injectRule android.TestingBuildParams
+	var provideNativeLibs, requireNativeLibs []string
+
+	injectRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("injectApexDependency")
+	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+	ensureListEmpty(t, provideNativeLibs)
+	ensureListEmpty(t, requireNativeLibs)
+
+	injectRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("injectApexDependency")
+	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+	ensureListEmpty(t, provideNativeLibs)
+	ensureListContains(t, requireNativeLibs, "libfoo.so")
+
+	injectRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("injectApexDependency")
+	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+	ensureListContains(t, provideNativeLibs, "libfoo.so")
+	ensureListEmpty(t, requireNativeLibs)
+
+	injectRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("injectApexDependency")
+	provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+	requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+	ensureListContains(t, provideNativeLibs, "libfoo.so")
+	ensureListEmpty(t, requireNativeLibs)
+}
+
 func TestNonTestApex(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
diff --git a/cc/cc.go b/cc/cc.go
index e96fba6..2bde2d3 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1887,7 +1887,7 @@
 			isVendorPublicLib := inList(libName, *vendorPublicLibraries)
 			bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
 
-			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() {
+			if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() && !c.inRecovery() {
 				// The vendor module is a no-vendor-variant VNDK library.  Depend on the
 				// core module instead.
 				return libName
diff --git a/cc/config/global.go b/cc/config/global.go
index a27246e..9ce6896 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -150,8 +150,22 @@
 	pctx.StaticVariable("HostGlobalLdflags", strings.Join(hostGlobalLdflags, " "))
 	pctx.StaticVariable("HostGlobalLldflags", strings.Join(hostGlobalLldflags, " "))
 
-	pctx.StaticVariable("CommonClangGlobalCflags",
-		strings.Join(append(ClangFilterUnknownCflags(commonGlobalCflags), "${ClangExtraCflags}"), " "))
+	pctx.VariableFunc("CommonClangGlobalCflags", func(ctx android.PackageVarContext) string {
+		flags := ClangFilterUnknownCflags(commonGlobalCflags)
+		flags = append(flags, "${ClangExtraCflags}")
+
+		// http://b/131390872
+		// Automatically initialize any uninitialized stack variables.
+		// Prefer zero-init if both options are set.
+		if ctx.Config().IsEnvTrue("AUTO_ZERO_INITIALIZE") {
+			flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang")
+		} else if ctx.Config().IsEnvTrue("AUTO_PATTERN_INITIALIZE") {
+			flags = append(flags, "-ftrivial-auto-var-init=pattern")
+		}
+
+		return strings.Join(flags, " ")
+	})
+
 	pctx.VariableFunc("DeviceClangGlobalCflags", func(ctx android.PackageVarContext) string {
 		if ctx.Config().Fuchsia() {
 			return strings.Join(ClangFilterUnknownCflags(deviceGlobalCflags), " ")
diff --git a/cc/lto.go b/cc/lto.go
index 1084869..431d70d 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -80,6 +80,12 @@
 }
 
 func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
+	// TODO(b/131771163): Disable LTO when using explicit fuzzing configurations.
+	// LTO breaks fuzzer builds.
+	if inList("-fsanitize=fuzzer-no-link", flags.CFlags) {
+		return flags
+	}
+
 	if lto.LTO() {
 		var ltoFlag string
 		if Bool(lto.Properties.Lto.Thin) {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 969cb3f..3747b41 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -54,6 +54,7 @@
 		"mediandk",
 		"nativewindow",
 		"m",
+		"neuralnetworks",
 		"OpenMAXAL",
 		"OpenSLES",
 		"stdc++",
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b238b7e..261ca88 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -464,7 +464,9 @@
 
 		// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
 		_, flags.LdFlags = removeFromList("-flto", flags.LdFlags)
+		_, flags.CFlags = removeFromList("-flto", flags.CFlags)
 		flags.LdFlags = append(flags.LdFlags, "-fno-lto")
+		flags.CFlags = append(flags.CFlags, "-fno-lto")
 
 		// TODO(b/133876586): Experimental PM breaks sanitizer coverage.
 		_, flags.CFlags = removeFromList("-fexperimental-new-pass-manager", flags.CFlags)
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 0bc3606..39303bf 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -331,42 +331,36 @@
 	}
 
 	buildActionFlags := []struct {
-		name              string
-		description       string
-		action            build.BuildAction
-		buildDependencies bool
-		set               bool
+		name        string
+		description string
+		action      build.BuildAction
+		set         bool
 	}{{
-		name:              "all-modules",
-		description:       "Build action: build from the top of the source tree.",
-		action:            build.BUILD_MODULES,
-		buildDependencies: true,
+		name:        "all-modules",
+		description: "Build action: build from the top of the source tree.",
+		action:      build.BUILD_MODULES,
 	}, {
-		// buildDependencies is set to true as mm is being deprecated. This is redirecting to mma build
-		// command behaviour. Once it has soaked for a while, the build command is deleted from here once
-		// it has been removed from the envsetup.sh.
-		name:              "modules-in-a-dir-no-deps",
-		description:       "Build action: builds all of the modules in the current directory without their dependencies.",
-		action:            build.BUILD_MODULES_IN_A_DIRECTORY,
-		buildDependencies: true,
+		// This is redirecting to mma build command behaviour. Once it has soaked for a
+		// while, the build command is deleted from here once it has been removed from the
+		// envsetup.sh.
+		name:        "modules-in-a-dir-no-deps",
+		description: "Build action: builds all of the modules in the current directory without their dependencies.",
+		action:      build.BUILD_MODULES_IN_A_DIRECTORY,
 	}, {
-		// buildDependencies is set to true as mmm is being deprecated. This is redirecting to mmma build
-		// command behaviour. Once it has soaked for a while, the build command is deleted from here once
-		// it has been removed from the envsetup.sh.
-		name:              "modules-in-dirs-no-deps",
-		description:       "Build action: builds all of the modules in the supplied directories without their dependencies.",
-		action:            build.BUILD_MODULES_IN_DIRECTORIES,
-		buildDependencies: true,
+		// This is redirecting to mmma build command behaviour. Once it has soaked for a
+		// while, the build command is deleted from here once it has been removed from the
+		// envsetup.sh.
+		name:        "modules-in-dirs-no-deps",
+		description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
+		action:      build.BUILD_MODULES_IN_DIRECTORIES,
 	}, {
-		name:              "modules-in-a-dir",
-		description:       "Build action: builds all of the modules in the current directory and their dependencies.",
-		action:            build.BUILD_MODULES_IN_A_DIRECTORY,
-		buildDependencies: true,
+		name:        "modules-in-a-dir",
+		description: "Build action: builds all of the modules in the current directory and their dependencies.",
+		action:      build.BUILD_MODULES_IN_A_DIRECTORY,
 	}, {
-		name:              "modules-in-dirs",
-		description:       "Build action: builds all of the modules in the supplied directories and their dependencies.",
-		action:            build.BUILD_MODULES_IN_DIRECTORIES,
-		buildDependencies: true,
+		name:        "modules-in-dirs",
+		description: "Build action: builds all of the modules in the supplied directories and their dependencies.",
+		action:      build.BUILD_MODULES_IN_DIRECTORIES,
 	}}
 	for i, flag := range buildActionFlags {
 		flags.BoolVar(&buildActionFlags[i].set, flag.name, false, flag.description)
@@ -386,12 +380,10 @@
 	// is specified.
 	buildActionCount := 0
 	var buildAction build.BuildAction
-	buildDependency := false
 	for _, flag := range buildActionFlags {
 		if flag.set {
 			buildActionCount++
 			buildAction = flag.action
-			buildDependency = flag.buildDependencies
 		}
 	}
 	if buildActionCount != 1 {
@@ -403,7 +395,7 @@
 
 	// Remove the build action flags from the args as they are not recognized by the config.
 	args = args[numBuildActionFlags:]
-	return build.NewBuildActionConfig(buildAction, *dir, buildDependency, ctx, args...)
+	return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
 }
 
 func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
@@ -425,17 +417,13 @@
 
 	if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
 		writer := ctx.Writer
-		fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is deprecated, and will be removed shortly.")
+		fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is obsolete.")
 		fmt.Fprintln(writer, "!")
 		fmt.Fprintln(writer, "! If you're using `mm`, you'll need to run `source build/envsetup.sh` to update.")
 		fmt.Fprintln(writer, "!")
 		fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...")
 		fmt.Fprintln(writer, "")
-		select {
-		case <-time.After(30 * time.Second):
-		case <-ctx.Done():
-			return
-		}
+		ctx.Fatal("done")
 	}
 
 	toBuild := build.BuildAll
diff --git a/java/app.go b/java/app.go
index a679e88..674e5ec 100644
--- a/java/app.go
+++ b/java/app.go
@@ -191,9 +191,12 @@
 	}
 }
 
+func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	a.generateAndroidBuildActions(ctx)
+}
+
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
-	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
+	a.checkPlatformAPI(ctx)
 	a.generateAndroidBuildActions(ctx)
 }
 
@@ -422,6 +425,9 @@
 func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
 	var apkDeps android.Paths
 
+	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
+	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
+
 	// Check if the install APK name needs to be overridden.
 	a.installApkName = ctx.DeviceConfig().OverridePackageNameFor(a.Name())
 
@@ -584,8 +590,6 @@
 			a.additionalAaptFlags = append(a.additionalAaptFlags, "--rename-instrumentation-target-package "+manifestPackageName)
 		}
 	}
-	a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx)
-	a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
 	a.generateAndroidBuildActions(ctx)
 
 	a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites)
diff --git a/java/app_test.go b/java/app_test.go
index 32de019..f6a307e 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -72,6 +72,7 @@
 			ctx := testApp(t, moduleType+` {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current"
 				}
 			`)
 
@@ -117,6 +118,7 @@
 					name: "foo",
 					srcs: ["a.java"],
 					package_splits: ["v4", "v7,hdpi"],
+					sdk_version: "current"
 				}`)
 
 	foo := ctx.ModuleForTests("foo", "android_common")
@@ -139,6 +141,40 @@
 	}
 }
 
+func TestPlatformAPIs(t *testing.T) {
+	testJava(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			platform_apis: true,
+		}
+	`)
+
+	testJava(t, `
+		android_app {
+			name: "foo",
+			srcs: ["a.java"],
+			sdk_version: "current",
+		}
+	`)
+
+	testJavaError(t, "platform_apis must be true when sdk_version is empty.", `
+		android_app {
+			name: "bar",
+			srcs: ["b.java"],
+		}
+	`)
+
+	testJavaError(t, "platform_apis must be false when sdk_version is not empty.", `
+		android_app {
+			name: "bar",
+			srcs: ["b.java"],
+			sdk_version: "system_current",
+			platform_apis: true,
+		}
+	`)
+}
+
 func TestResourceDirs(t *testing.T) {
 	testCases := []struct {
 		name      string
@@ -169,6 +205,7 @@
 	bp := `
 			android_app {
 				name: "foo",
+				sdk_version: "current",
 				%s
 			}
 		`
@@ -349,12 +386,14 @@
 	bp := `
 			android_app {
 				name: "foo",
+				sdk_version: "current",
 				resource_dirs: ["foo/res"],
 				static_libs: ["lib", "lib3"],
 			}
 
 			android_app {
 				name: "bar",
+				sdk_version: "current",
 				resource_dirs: ["bar/res"],
 			}
 
@@ -461,6 +500,7 @@
 		platformSdkCodename   string
 		platformSdkFinal      bool
 		expectedMinSdkVersion string
+		platformApis          bool
 	}{
 		{
 			name:                  "current final SDK",
@@ -481,6 +521,7 @@
 		{
 			name:                  "default final SDK",
 			sdkVersion:            "",
+			platformApis:          true,
 			platformSdkInt:        27,
 			platformSdkCodename:   "REL",
 			platformSdkFinal:      true,
@@ -489,6 +530,7 @@
 		{
 			name:                  "default non-final SDK",
 			sdkVersion:            "",
+			platformApis:          true,
 			platformSdkInt:        27,
 			platformSdkCodename:   "OMR1",
 			platformSdkFinal:      false,
@@ -504,11 +546,16 @@
 	for _, moduleType := range []string{"android_app", "android_library"} {
 		for _, test := range testCases {
 			t.Run(moduleType+" "+test.name, func(t *testing.T) {
+				platformApiProp := ""
+				if test.platformApis {
+					platformApiProp = "platform_apis: true,"
+				}
 				bp := fmt.Sprintf(`%s {
 					name: "foo",
 					srcs: ["a.java"],
 					sdk_version: "%s",
-				}`, moduleType, test.sdkVersion)
+					%s
+				}`, moduleType, test.sdkVersion, platformApiProp)
 
 				config := testConfig(nil)
 				config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
@@ -630,18 +677,21 @@
 		android_app {
 			name: "app",
 			jni_libs: ["libjni"],
+			sdk_version: "current",
 		}
 
 		android_app {
 			name: "app_noembed",
 			jni_libs: ["libjni"],
 			use_embedded_native_libs: false,
+			sdk_version: "current",
 		}
 
 		android_app {
 			name: "app_embed",
 			jni_libs: ["libjni"],
 			use_embedded_native_libs: true,
+			sdk_version: "current",
 		}
 
 		android_test {
@@ -715,6 +765,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			certificateOverride: "",
@@ -726,7 +777,8 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
-					certificate: ":new_certificate"
+					certificate: ":new_certificate",
+					sdk_version: "current",
 				}
 
 				android_app_certificate {
@@ -743,7 +795,8 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
-					certificate: "expiredkey"
+					certificate: "expiredkey",
+					sdk_version: "current",
 				}
 			`,
 			certificateOverride: "",
@@ -755,7 +808,8 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
-					certificate: "expiredkey"
+					certificate: "expiredkey",
+					sdk_version: "current",
 				}
 
 				android_app_certificate {
@@ -801,6 +855,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			packageNameOverride: "",
@@ -815,6 +870,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			packageNameOverride: "foo:bar",
@@ -856,11 +912,13 @@
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}
 
 		android_test {
 			name: "bar",
 			instrumentation_for: "foo",
+			sdk_version: "current",
 		}
 		`
 	config := testConfig(nil)
@@ -885,6 +943,7 @@
 			srcs: ["a.java"],
 			certificate: "expiredkey",
 			overrides: ["qux"],
+			sdk_version: "current",
 		}
 
 		override_android_app {
@@ -984,6 +1043,7 @@
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
+			sdk_version: "current",
 		}
 
 		override_android_app {
@@ -1253,18 +1313,21 @@
 			name: "foo",
 			srcs: ["a.java"],
 			api_packages: ["foo"],
+			sdk_version: "current",
 		}
 
 		java_sdk_library {
 			name: "bar",
 			srcs: ["a.java"],
 			api_packages: ["bar"],
+			sdk_version: "current",
 		}
 
 		android_app {
 			name: "app",
 			srcs: ["a.java"],
 			uses_libs: ["foo"],
+			sdk_version: "current",
 			optional_uses_libs: [
 				"bar",
 				"baz",
@@ -1339,6 +1402,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			noCode: false,
@@ -1348,6 +1412,7 @@
 			bp: `
 				android_app {
 					name: "foo",
+					sdk_version: "current",
 				}
 			`,
 			noCode: true,
@@ -1358,11 +1423,13 @@
 				android_app {
 					name: "foo",
 					static_libs: ["lib"],
+					sdk_version: "current",
 				}
 
 				java_library {
 					name: "lib",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			noCode: false,
@@ -1373,10 +1440,12 @@
 				android_app {
 					name: "foo",
 					static_libs: ["lib"],
+					sdk_version: "current",
 				}
 
 				java_library {
 					name: "lib",
+					sdk_version: "current",
 				}
 			`,
 			// TODO(jungjw): this should probably be true
@@ -1406,6 +1475,7 @@
 			jni_libs: ["libjni"],
 			notice: "APP_NOTICE",
 			embed_notices: true,
+			sdk_version: "current",
 		}
 
 		// No embed_notice flag
@@ -1414,6 +1484,7 @@
 			srcs: ["a.java"],
 			jni_libs: ["libjni"],
 			notice: "APP_NOTICE",
+			sdk_version: "current",
 		}
 
 		// No NOTICE files
@@ -1421,6 +1492,7 @@
 			name: "baz",
 			srcs: ["a.java"],
 			embed_notices: true,
+			sdk_version: "current",
 		}
 
 		cc_library {
@@ -1435,6 +1507,7 @@
 			srcs: [
 				":gen",
 			],
+			sdk_version: "current",
 		}
 
 		genrule {
@@ -1510,6 +1583,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			uncompressedPlatform:  true,
@@ -1522,6 +1596,7 @@
 					name: "foo",
 					use_embedded_dex: true,
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			uncompressedPlatform:  true,
@@ -1534,6 +1609,7 @@
 					name: "foo",
 					privileged: true,
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}
 			`,
 			uncompressedPlatform:  true,
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 22b7bb9..5550a4c 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -30,6 +30,7 @@
 				android_app {
 					name: "foo",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}`,
 			enabled: true,
 		},
@@ -57,6 +58,7 @@
 			bp: `
 				android_app {
 					name: "foo",
+					sdk_version: "current",
 				}`,
 			enabled: false,
 		},
@@ -66,11 +68,13 @@
 				android_app {
 					name: "foo",
 					static_libs: ["lib"],
+					sdk_version: "current",
 				}
 
 				java_library {
 					name: "lib",
 					srcs: ["a.java"],
+					sdk_version: "current",
 				}`,
 			enabled: true,
 		},
diff --git a/java/java.go b/java/java.go
index fb2ddf9..fea38b5 100644
--- a/java/java.go
+++ b/java/java.go
@@ -53,6 +53,20 @@
 	android.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
 }
 
+func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
+	if sc, ok := ctx.Module().(sdkContext); ok {
+		usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
+		if usePlatformAPI != (sc.sdkVersion() == "") {
+			if usePlatformAPI {
+				ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
+			} else {
+				ctx.PropertyErrorf("platform_apis", "platform_apis must be true when sdk_version is empty.")
+			}
+		}
+
+	}
+}
+
 // TODO:
 // Autogenerated files:
 //  Renderscript
@@ -179,8 +193,8 @@
 	// list of module-specific flags that will be used for dex compiles
 	Dxflags []string `android:"arch_variant"`
 
-	// if not blank, set to the version of the sdk to compile against.  Defaults to compiling against the current
-	// sdk if platform_apis is not set.
+	// if not blank, set to the version of the sdk to compile against.
+	// Defaults to compiling against the current platform.
 	Sdk_version *string
 
 	// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
@@ -191,7 +205,8 @@
 	// Defaults to sdk_version if not set.
 	Target_sdk_version *string
 
-	// if true, compile against the platform APIs instead of an SDK.
+	// It must be true only if sdk_version is empty.
+	// This field works in only android_app, otherwise nothing happens.
 	Platform_apis *bool
 
 	Aidl struct {
diff --git a/java/java_test.go b/java/java_test.go
index f95f88b..81d1f2c 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -222,6 +222,29 @@
 	android.FailIfErrored(t, errs)
 }
 
+func testJavaError(t *testing.T, pattern string, bp string) {
+	t.Helper()
+	config := testConfig(nil)
+	ctx := testContext(bp, nil)
+
+	pathCtx := android.PathContextForTesting(config, nil)
+	setDexpreoptTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
+
+	ctx.Register()
+	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
+	if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+	_, errs = ctx.PrepareBuildActions(config)
+	if len(errs) > 0 {
+		android.FailIfNoMatchingErrors(t, pattern, errs)
+		return
+	}
+
+	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
 func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) {
 	t.Helper()
 	config := testConfig(nil)
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 31f5922..8c59cbc 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -69,3 +69,19 @@
     },
     test_suites: ["general-tests"],
 }
+
+python_binary_host {
+    name: "jsonmodify",
+    main: "jsonmodify.py",
+    srcs: [
+        "jsonmodify.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    }
+}
diff --git a/scripts/jsonmodify.py b/scripts/jsonmodify.py
new file mode 100755
index 0000000..4b2c3c2
--- /dev/null
+++ b/scripts/jsonmodify.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import argparse
+import collections
+import json
+import sys
+
+def follow_path(obj, path):
+  cur = obj
+  last_key = None
+  for key in path.split('.'):
+    if last_key:
+      if last_key not in cur:
+        return None,None
+      cur = cur[last_key]
+    last_key = key
+  if last_key not in cur:
+    return None,None
+  return cur, last_key
+
+
+def ensure_path(obj, path):
+  cur = obj
+  last_key = None
+  for key in path.split('.'):
+    if last_key:
+      if last_key not in cur:
+        cur[last_key] = dict()
+      cur = cur[last_key]
+    last_key = key
+  return cur, last_key
+
+
+class SetValue(str):
+  def apply(self, obj, val):
+    cur, key = ensure_path(obj, self)
+    cur[key] = val
+
+
+class Replace(str):
+  def apply(self, obj, val):
+    cur, key = follow_path(obj, self)
+    if cur:
+      cur[key] = val
+
+
+class Remove(str):
+  def apply(self, obj):
+    cur, key = follow_path(obj, self)
+    if cur:
+      del cur[key]
+
+
+class AppendList(str):
+  def apply(self, obj, *args):
+    cur, key = ensure_path(obj, self)
+    if key not in cur:
+      cur[key] = list()
+    if not isinstance(cur[key], list):
+      raise ValueError(self + " should be a array.")
+    cur[key].extend(args)
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument('-o', '--out',
+                      help='write result to a file. If omitted, print to stdout',
+                      metavar='output',
+                      action='store')
+  parser.add_argument('input', nargs='?', help='JSON file')
+  parser.add_argument("-v", "--value", type=SetValue,
+                      help='set value of the key specified by path. If path doesn\'t exist, creates new one.',
+                      metavar=('path', 'value'),
+                      nargs=2, dest='patch', default=[], action='append')
+  parser.add_argument("-s", "--replace", type=Replace,
+                      help='replace value of the key specified by path. If path doesn\'t exist, no op.',
+                      metavar=('path', 'value'),
+                      nargs=2, dest='patch', action='append')
+  parser.add_argument("-r", "--remove", type=Remove,
+                      help='remove the key specified by path. If path doesn\'t exist, no op.',
+                      metavar='path',
+                      nargs=1, dest='patch', action='append')
+  parser.add_argument("-a", "--append_list", type=AppendList,
+                      help='append values to the list specified by path. If path doesn\'t exist, creates new list for it.',
+                      metavar=('path', 'value'),
+                      nargs='+', dest='patch', default=[], action='append')
+  args = parser.parse_args()
+
+  if args.input:
+    with open(args.input) as f:
+      obj = json.load(f, object_pairs_hook=collections.OrderedDict)
+  else:
+    obj = json.load(sys.stdin, object_pairs_hook=collections.OrderedDict)
+
+  for p in args.patch:
+    p[0].apply(obj, *p[1:])
+
+  if args.out:
+    with open(args.out, "w") as f:
+      json.dump(obj, f, indent=2)
+  else:
+    print(json.dumps(obj, indent=2))
+
+
+if __name__ == '__main__':
+  main()
diff --git a/ui/build/config.go b/ui/build/config.go
index bcb1965..434047b 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -253,13 +253,13 @@
 
 // NewBuildActionConfig returns a build configuration based on the build action. The arguments are
 // processed based on the build action and extracts any arguments that belongs to the build action.
-func NewBuildActionConfig(action BuildAction, dir string, buildDependencies bool, ctx Context, args ...string) Config {
-	return NewConfig(ctx, getConfigArgs(action, dir, buildDependencies, ctx, args)...)
+func NewBuildActionConfig(action BuildAction, dir string, ctx Context, args ...string) Config {
+	return NewConfig(ctx, getConfigArgs(action, dir, ctx, args)...)
 }
 
 // getConfigArgs processes the command arguments based on the build action and creates a set of new
 // arguments to be accepted by Config.
-func getConfigArgs(action BuildAction, dir string, buildDependencies bool, ctx Context, args []string) []string {
+func getConfigArgs(action BuildAction, dir string, ctx Context, args []string) []string {
 	// The next block of code verifies that the current directory is the root directory of the source
 	// tree. It then finds the relative path of dir based on the root directory of the source tree
 	// and verify that dir is inside of the source tree.
@@ -295,7 +295,6 @@
 		configArgs = removeFromList("GET-INSTALL-PATH", configArgs)
 	}
 
-	var buildFiles []string
 	var targets []string
 
 	switch action {
@@ -312,20 +311,11 @@
 		if buildFile == "" {
 			ctx.Fatalf("Build file not found for %s directory", relDir)
 		}
-		buildFiles = []string{buildFile}
 		targets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
 	case BUILD_MODULES_IN_DIRECTORIES:
 		newConfigArgs, dirs := splitArgs(configArgs)
 		configArgs = newConfigArgs
-		targets, buildFiles = getTargetsFromDirs(ctx, relDir, dirs, targetNamePrefix)
-	}
-
-	// This is to support building modules without building their dependencies. Soon, this will be
-	// deprecated.
-	if !buildDependencies && len(buildFiles) > 0 {
-		if err := os.Setenv("ONE_SHOT_MAKEFILE", strings.Join(buildFiles, " ")); err != nil {
-			ctx.Fatalf("Unable to set ONE_SHOT_MAKEFILE environment variable: %v", err)
-		}
+		targets = getTargetsFromDirs(ctx, relDir, dirs, targetNamePrefix)
 	}
 
 	// Tidy only override all other specified targets.
@@ -435,7 +425,7 @@
 // directory from the dirs list does not exist, a fatal error is raised. relDir is related to the
 // source root tree where the build action command was invoked. Each directory is validated if the
 // build file can be found and follows the format "dir1:target1,target2,...". Target is optional.
-func getTargetsFromDirs(ctx Context, relDir string, dirs []string, targetNamePrefix string) (targets []string, buildFiles []string) {
+func getTargetsFromDirs(ctx Context, relDir string, dirs []string, targetNamePrefix string) (targets []string) {
 	for _, dir := range dirs {
 		// The directory may have specified specific modules to build. ":" is the separator to separate
 		// the directory and the list of modules.
@@ -466,20 +456,18 @@
 			if !hasBuildFile(ctx, dir) {
 				ctx.Fatalf("Couldn't locate a build file from %s directory", dir)
 			}
-			buildFiles = append(buildFiles, filepath.Join(dir, "Android.mk"))
 		} else {
 			buildFile := findBuildFile(ctx, dir)
 			if buildFile == "" {
 				ctx.Fatalf("Build file not found for %s directory", dir)
 			}
 			newTargets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
-			buildFiles = append(buildFiles, buildFile)
 		}
 
 		targets = append(targets, newTargets...)
 	}
 
-	return targets, buildFiles
+	return targets
 }
 
 func (c *configImpl) parseArgs(ctx Context, args []string) {
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 463405a..df618c4 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -363,19 +363,15 @@
 		// Expected targets from the function.
 		expectedTargets []string
 
-		// Expected build from the build system.
-		expectedBuildFiles []string
-
 		// Expecting error from running test case.
 		errStr string
 	}{{
-		description:        "one target dir specified",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/3/Android.bp"},
-		dirs:               []string{"1/2/3"},
-		curDir:             "0",
-		expectedTargets:    []string{"MODULES-IN-0-1-2-3"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+		description:     "one target dir specified",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/3/Android.bp"},
+		dirs:            []string{"1/2/3"},
+		curDir:          "0",
+		expectedTargets: []string{"MODULES-IN-0-1-2-3"},
 	}, {
 		description: "one target dir specified, build file does not exist",
 		dirsInTrees: []string{"0/1/2/3"},
@@ -391,21 +387,19 @@
 		curDir:      "0",
 		errStr:      "1/2/3:t1:t2 not in proper directory:target1,target2,... format (\":\" was specified more than once)",
 	}, {
-		description:        "one target dir specified, no targets specified but has colon",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/3/Android.bp"},
-		dirs:               []string{"1/2/3:"},
-		curDir:             "0",
-		expectedTargets:    []string{"MODULES-IN-0-1-2-3"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+		description:     "one target dir specified, no targets specified but has colon",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/3/Android.bp"},
+		dirs:            []string{"1/2/3:"},
+		curDir:          "0",
+		expectedTargets: []string{"MODULES-IN-0-1-2-3"},
 	}, {
-		description:        "one target dir specified, two targets specified",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/3/Android.bp"},
-		dirs:               []string{"1/2/3:t1,t2"},
-		curDir:             "0",
-		expectedTargets:    []string{"t1", "t2"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+		description:     "one target dir specified, two targets specified",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/3/Android.bp"},
+		dirs:            []string{"1/2/3:t1,t2"},
+		curDir:          "0",
+		expectedTargets: []string{"t1", "t2"},
 	}, {
 		description: "one target dir specified, no targets and has a comma",
 		dirsInTrees: []string{"0/1/2/3"},
@@ -428,13 +422,12 @@
 		curDir:      "0",
 		errStr:      "0/1/2/3 not in proper directory:target1,target2,... format",
 	}, {
-		description:        "one target dir specified, many targets specified",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/3/Android.bp"},
-		dirs:               []string{"1/2/3:t1,t2,t3,t4,t5,t6,t7,t8,t9,t10"},
-		curDir:             "0",
-		expectedTargets:    []string{"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+		description:     "one target dir specified, many targets specified",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/3/Android.bp"},
+		dirs:            []string{"1/2/3:t1,t2,t3,t4,t5,t6,t7,t8,t9,t10"},
+		curDir:          "0",
+		expectedTargets: []string{"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10"},
 	}, {
 		description: "one target dir specified, one target specified, build file does not exist",
 		dirsInTrees: []string{"0/1/2/3"},
@@ -450,29 +443,26 @@
 		curDir:      "0",
 		errStr:      "Couldn't locate a build file from 0/1/2/3 directory",
 	}, {
-		description:        "one target dir specified, build file not in target dir",
-		dirsInTrees:        []string{"0/1/2/3"},
-		buildFiles:         []string{"0/1/2/Android.mk"},
-		dirs:               []string{"1/2/3"},
-		curDir:             "0",
-		expectedTargets:    []string{"MODULES-IN-0-1-2"},
-		expectedBuildFiles: []string{"0/1/2/Android.mk"},
+		description:     "one target dir specified, build file not in target dir",
+		dirsInTrees:     []string{"0/1/2/3"},
+		buildFiles:      []string{"0/1/2/Android.mk"},
+		dirs:            []string{"1/2/3"},
+		curDir:          "0",
+		expectedTargets: []string{"MODULES-IN-0-1-2"},
 	}, {
-		description:        "multiple targets dir specified, targets specified",
-		dirsInTrees:        []string{"0/1/2/3", "0/3/4"},
-		buildFiles:         []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
-		dirs:               []string{"1/2/3:t1,t2", "3/4:t3,t4,t5"},
-		curDir:             "0",
-		expectedTargets:    []string{"t1", "t2", "t3", "t4", "t5"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
+		description:     "multiple targets dir specified, targets specified",
+		dirsInTrees:     []string{"0/1/2/3", "0/3/4"},
+		buildFiles:      []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
+		dirs:            []string{"1/2/3:t1,t2", "3/4:t3,t4,t5"},
+		curDir:          "0",
+		expectedTargets: []string{"t1", "t2", "t3", "t4", "t5"},
 	}, {
-		description:        "multiple targets dir specified, one directory has targets specified",
-		dirsInTrees:        []string{"0/1/2/3", "0/3/4"},
-		buildFiles:         []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
-		dirs:               []string{"1/2/3:t1,t2", "3/4"},
-		curDir:             "0",
-		expectedTargets:    []string{"t1", "t2", "MODULES-IN-0-3-4"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
+		description:     "multiple targets dir specified, one directory has targets specified",
+		dirsInTrees:     []string{"0/1/2/3", "0/3/4"},
+		buildFiles:      []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
+		dirs:            []string{"1/2/3:t1,t2", "3/4"},
+		curDir:          "0",
+		expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
 	}, {
 		description: "two dirs specified, only one dir exist",
 		dirsInTrees: []string{"0/1/2/3"},
@@ -481,13 +471,12 @@
 		curDir:      "0",
 		errStr:      "couldn't find directory 0/3/4",
 	}, {
-		description:        "multiple targets dirs specified at root source tree",
-		dirsInTrees:        []string{"0/1/2/3", "0/3/4"},
-		buildFiles:         []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
-		dirs:               []string{"0/1/2/3:t1,t2", "0/3/4"},
-		curDir:             ".",
-		expectedTargets:    []string{"t1", "t2", "MODULES-IN-0-3-4"},
-		expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
+		description:     "multiple targets dirs specified at root source tree",
+		dirsInTrees:     []string{"0/1/2/3", "0/3/4"},
+		buildFiles:      []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
+		dirs:            []string{"0/1/2/3:t1,t2", "0/3/4"},
+		curDir:          ".",
+		expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
 	}, {
 		description: "no directories specified",
 		dirsInTrees: []string{"0/1/2/3", "0/3/4"},
@@ -518,13 +507,10 @@
 			r := setTop(t, topDir)
 			defer r()
 
-			targets, buildFiles := getTargetsFromDirs(ctx, tt.curDir, tt.dirs, "MODULES-IN-")
+			targets := getTargetsFromDirs(ctx, tt.curDir, tt.dirs, "MODULES-IN-")
 			if !reflect.DeepEqual(targets, tt.expectedTargets) {
 				t.Errorf("expected %v, got %v for targets", tt.expectedTargets, targets)
 			}
-			if !reflect.DeepEqual(buildFiles, tt.expectedBuildFiles) {
-				t.Errorf("expected %v, got %v for build files", tt.expectedBuildFiles, buildFiles)
-			}
 
 			// If the execution reached here and there was an expected error code, the unit test case failed.
 			if tt.errStr != "" {
@@ -732,14 +718,11 @@
 	// Expected arguments to be in Config instance.
 	expectedArgs []string
 
-	// Expected environment variables to be set.
-	expectedEnvVars []envVar
-
 	// Expecting error from running test case.
 	expectedErrStr string
 }
 
-func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction, buildDependencies bool) {
+func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction) {
 	ctx := testContext()
 
 	defer logger.Recover(func(err error) {
@@ -753,7 +736,6 @@
 
 	// Environment variables to set it to blank on every test case run.
 	resetEnvVars := []string{
-		"ONE_SHOT_MAKEFILE",
 		"WITH_TIDY_ONLY",
 	}
 
@@ -807,17 +789,11 @@
 		t.Fatalf("failed to create %s file: %v", srcDirFileCheck, err)
 	}
 
-	args := getConfigArgs(action, tt.curDir, buildDependencies, ctx, tt.args)
+	args := getConfigArgs(action, tt.curDir, ctx, tt.args)
 	if !reflect.DeepEqual(tt.expectedArgs, args) {
 		t.Fatalf("expected %v, got %v for config arguments", tt.expectedArgs, args)
 	}
 
-	for _, env := range tt.expectedEnvVars {
-		if val := os.Getenv(env.name); val != env.value {
-			t.Errorf("expecting %s, got %s for environment variable %s", env.value, val, env.name)
-		}
-	}
-
 	// If the execution reached here and there was an expected error code, the unit test case failed.
 	if tt.expectedErrStr != "" {
 		t.Errorf("expecting error %s", tt.expectedErrStr)
@@ -826,299 +802,143 @@
 
 func TestGetConfigArgsBuildModules(t *testing.T) {
 	tests := []buildActionTestCase{{
-		description:     "normal execution from the root source tree directory",
-		dirsInTrees:     []string{"0/1/2", "0/2", "0/3"},
-		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp", "0/3/Android.mk"},
-		args:            []string{"-j", "fake_module", "fake_module2"},
-		curDir:          ".",
-		tidyOnly:        "",
-		expectedArgs:    []string{"-j", "fake_module", "fake_module2"},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution from the root source tree directory",
+		dirsInTrees:  []string{"0/1/2", "0/2", "0/3"},
+		buildFiles:   []string{"0/1/2/Android.mk", "0/2/Android.bp", "0/3/Android.mk"},
+		args:         []string{"-j", "fake_module", "fake_module2"},
+		curDir:       ".",
+		tidyOnly:     "",
+		expectedArgs: []string{"-j", "fake_module", "fake_module2"},
 	}, {
-		description:     "normal execution in deep directory",
-		dirsInTrees:     []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
-		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
-		args:            []string{"-j", "fake_module", "fake_module2", "-k"},
-		curDir:          "1/2/3/4/5/6/7/8/9",
-		tidyOnly:        "",
-		expectedArgs:    []string{"-j", "fake_module", "fake_module2", "-k"},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution in deep directory",
+		dirsInTrees:  []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
+		buildFiles:   []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
+		args:         []string{"-j", "fake_module", "fake_module2", "-k"},
+		curDir:       "1/2/3/4/5/6/7/8/9",
+		tidyOnly:     "",
+		expectedArgs: []string{"-j", "fake_module", "fake_module2", "-k"},
 	}, {
-		description:     "normal execution in deep directory, no targets",
-		dirsInTrees:     []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
-		buildFiles:      []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
-		args:            []string{"-j", "-k"},
-		curDir:          "1/2/3/4/5/6/7/8/9",
-		tidyOnly:        "",
-		expectedArgs:    []string{"-j", "-k"},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution in deep directory, no targets",
+		dirsInTrees:  []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
+		buildFiles:   []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
+		args:         []string{"-j", "-k"},
+		curDir:       "1/2/3/4/5/6/7/8/9",
+		tidyOnly:     "",
+		expectedArgs: []string{"-j", "-k"},
 	}, {
-		description:     "normal execution in 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"},
-		args:            []string{},
-		curDir:          "0/2",
-		tidyOnly:        "",
-		expectedArgs:    []string{},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution in 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"},
+		args:         []string{},
+		curDir:       "0/2",
+		tidyOnly:     "",
+		expectedArgs: []string{},
 	}, {
-		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{},
+		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{},
 	}}
 	for _, tt := range tests {
 		t.Run("build action BUILD_MODULES with dependencies, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES, true)
-		})
-	}
-}
-
-// TODO: Remove this test case once mm shell build command has been deprecated.
-func TestGetConfigArgsBuildModulesInDirecotoryNoDeps(t *testing.T) {
-	tests := []buildActionTestCase{{
-		description:  "normal execution in a directory",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/2/Android.mk"},
-		args:         []string{"-j", "-k", "showcommands", "fake-module"},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"-j", "-k", "showcommands", "fake-module", "MODULES-IN-0-1-2"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/Android.mk"}},
-	}, {
-		description:  "makefile in parent directory",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/Android.mk"},
-		args:         []string{},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"MODULES-IN-0-1"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/Android.mk"}},
-	}, {
-		description:  "build file not found",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{},
-		args:         []string{},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"MODULES-IN-0-1-2"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/Android.mk"}},
-		expectedErrStr: "Build file not found for 0/1/2 directory",
-	}, {
-		description:  "build action executed at root directory",
-		dirsInTrees:  []string{},
-		buildFiles:   []string{},
-		args:         []string{},
-		curDir:       ".",
-		tidyOnly:     "",
-		expectedArgs: []string{},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
-	}, {
-		description:  "GET-INSTALL-PATH specified,",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/Android.mk"},
-		args:         []string{"GET-INSTALL-PATH"},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/Android.mk"}},
-	}, {
-		description:  "tidy only environment variable specified,",
-		dirsInTrees:  []string{"0/1/2"},
-		buildFiles:   []string{"0/1/Android.mk"},
-		args:         []string{"GET-INSTALL-PATH"},
-		curDir:       "0/1/2",
-		tidyOnly:     "true",
-		expectedArgs: []string{"tidy_only"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/Android.mk"}},
-	}}
-	for _, tt := range tests {
-		t.Run("build action BUILD_MODULES_IN_DIR without their dependencies, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY, false)
+			testGetConfigArgs(t, tt, BUILD_MODULES)
 		})
 	}
 }
 
 func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) {
 	tests := []buildActionTestCase{{
-		description:     "normal execution in a directory",
-		dirsInTrees:     []string{"0/1/2"},
-		buildFiles:      []string{"0/1/2/Android.mk"},
-		args:            []string{"fake-module"},
-		curDir:          "0/1/2",
-		tidyOnly:        "",
-		expectedArgs:    []string{"fake-module", "MODULES-IN-0-1-2"},
-		expectedEnvVars: []envVar{},
+		description:  "normal execution in a directory",
+		dirsInTrees:  []string{"0/1/2"},
+		buildFiles:   []string{"0/1/2/Android.mk"},
+		args:         []string{"fake-module"},
+		curDir:       "0/1/2",
+		tidyOnly:     "",
+		expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
 	}, {
-		description:     "build file in parent directory",
-		dirsInTrees:     []string{"0/1/2"},
-		buildFiles:      []string{"0/1/Android.mk"},
-		args:            []string{},
-		curDir:          "0/1/2",
-		tidyOnly:        "",
-		expectedArgs:    []string{"MODULES-IN-0-1"},
-		expectedEnvVars: []envVar{},
+		description:  "build file in parent directory",
+		dirsInTrees:  []string{"0/1/2"},
+		buildFiles:   []string{"0/1/Android.mk"},
+		args:         []string{},
+		curDir:       "0/1/2",
+		tidyOnly:     "",
+		expectedArgs: []string{"MODULES-IN-0-1"},
 	},
 		{
-			description:     "build file in parent directory, multiple module names passed in",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{"0/1/Android.mk"},
-			args:            []string{"fake-module1", "fake-module2", "fake-module3"},
-			curDir:          "0/1/2",
-			tidyOnly:        "",
-			expectedArgs:    []string{"fake-module1", "fake-module2", "fake-module3", "MODULES-IN-0-1"},
-			expectedEnvVars: []envVar{},
+			description:  "build file in parent directory, multiple module names passed in",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/1/Android.mk"},
+			args:         []string{"fake-module1", "fake-module2", "fake-module3"},
+			curDir:       "0/1/2",
+			tidyOnly:     "",
+			expectedArgs: []string{"fake-module1", "fake-module2", "fake-module3", "MODULES-IN-0-1"},
 		}, {
-			description:     "build file in 2nd level parent directory",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{"0/Android.bp"},
-			args:            []string{},
-			curDir:          "0/1/2",
-			tidyOnly:        "",
-			expectedArgs:    []string{"MODULES-IN-0"},
-			expectedEnvVars: []envVar{},
+			description:  "build file in 2nd level parent directory",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/Android.bp"},
+			args:         []string{},
+			curDir:       "0/1/2",
+			tidyOnly:     "",
+			expectedArgs: []string{"MODULES-IN-0"},
 		}, {
-			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",
+			dirsInTrees:  []string{},
+			buildFiles:   []string{},
+			rootSymlink:  false,
+			args:         []string{},
+			curDir:       ".",
+			tidyOnly:     "",
+			expectedArgs: []string{},
 		}, {
-			description:     "build action executed at root directory in symlink",
-			dirsInTrees:     []string{},
-			buildFiles:      []string{},
-			rootSymlink:     true,
-			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:     "",
+			expectedArgs: []string{},
 		}, {
-			description:     "build file not found",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{},
-			args:            []string{},
-			curDir:          "0/1/2",
-			tidyOnly:        "",
-			expectedArgs:    []string{"MODULES-IN-0-1-2"},
-			expectedEnvVars: []envVar{},
-			expectedErrStr:  "Build file not found for 0/1/2 directory",
+			description:    "build file not found",
+			dirsInTrees:    []string{"0/1/2"},
+			buildFiles:     []string{},
+			args:           []string{},
+			curDir:         "0/1/2",
+			tidyOnly:       "",
+			expectedArgs:   []string{"MODULES-IN-0-1-2"},
+			expectedErrStr: "Build file not found for 0/1/2 directory",
 		}, {
-			description:     "GET-INSTALL-PATH specified,",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{"0/1/Android.mk"},
-			args:            []string{"GET-INSTALL-PATH", "-j", "-k", "GET-INSTALL-PATH"},
-			curDir:          "0/1/2",
-			tidyOnly:        "",
-			expectedArgs:    []string{"-j", "-k", "GET-INSTALL-PATH-IN-0-1"},
-			expectedEnvVars: []envVar{},
+			description:  "GET-INSTALL-PATH specified,",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/1/Android.mk"},
+			args:         []string{"GET-INSTALL-PATH", "-j", "-k", "GET-INSTALL-PATH"},
+			curDir:       "0/1/2",
+			tidyOnly:     "",
+			expectedArgs: []string{"-j", "-k", "GET-INSTALL-PATH-IN-0-1"},
 		}, {
-			description:     "tidy only environment variable specified,",
-			dirsInTrees:     []string{"0/1/2"},
-			buildFiles:      []string{"0/1/Android.mk"},
-			args:            []string{"GET-INSTALL-PATH"},
-			curDir:          "0/1/2",
-			tidyOnly:        "true",
-			expectedArgs:    []string{"tidy_only"},
-			expectedEnvVars: []envVar{},
+			description:  "tidy only environment variable specified,",
+			dirsInTrees:  []string{"0/1/2"},
+			buildFiles:   []string{"0/1/Android.mk"},
+			args:         []string{"GET-INSTALL-PATH"},
+			curDir:       "0/1/2",
+			tidyOnly:     "true",
+			expectedArgs: []string{"tidy_only"},
 		}, {
-			description:     "normal execution in root directory with args",
-			dirsInTrees:     []string{},
-			buildFiles:      []string{},
-			args:            []string{"-j", "-k", "fake_module"},
-			curDir:          "",
-			tidyOnly:        "",
-			expectedArgs:    []string{"-j", "-k", "fake_module"},
-			expectedEnvVars: []envVar{},
+			description:  "normal execution in root directory with args",
+			dirsInTrees:  []string{},
+			buildFiles:   []string{},
+			args:         []string{"-j", "-k", "fake_module"},
+			curDir:       "",
+			tidyOnly:     "",
+			expectedArgs: []string{"-j", "-k", "fake_module"},
 		}}
 	for _, tt := range tests {
 		t.Run("build action BUILD_MODULES_IN_DIR, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY, true)
-		})
-	}
-}
-
-// TODO: Remove this test case once mmm shell build command has been deprecated.
-func TestGetConfigArgsBuildModulesInDirectoriesNoDeps(t *testing.T) {
-	tests := []buildActionTestCase{{
-		description:  "normal execution in a directory",
-		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
-		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
-		args:         []string{"3.1/:t1,t2", "3.2/:t3,t4", "3.3/:t5,t6"},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"t1", "t2", "t3", "t4", "t5", "t6"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
-	}, {
-		description:  "GET-INSTALL-PATH specified",
-		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
-		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
-		args:         []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3/:t6"},
-		curDir:       "0/1/2",
-		tidyOnly:     "",
-		expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "t6"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
-	}, {
-		description:  "tidy only environment variable specified",
-		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
-		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
-		args:         []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3/:t6"},
-		curDir:       "0/1/2",
-		tidyOnly:     "1",
-		expectedArgs: []string{"tidy_only"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
-	}, {
-		description:  "normal execution from top dir directory",
-		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
-		buildFiles:   []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
-		args:         []string{"0/1/2/3.1", "0/1/2/3.2/:t3,t4", "0/1/2/3.3/:t5,t6"},
-		curDir:       ".",
-		tidyOnly:     "",
-		expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "t3", "t4", "t5", "t6"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
-	}}
-	for _, tt := range tests {
-		t.Run("build action BUILD_MODULES_IN_DIRS_NO_DEPS, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES, false)
+			testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY)
 		})
 	}
 }
@@ -1132,10 +952,6 @@
 		curDir:       "0/1/2",
 		tidyOnly:     "",
 		expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-2-3.3"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
 	}, {
 		description:  "GET-INSTALL-PATH specified",
 		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3"},
@@ -1144,10 +960,6 @@
 		curDir:       "0/1",
 		tidyOnly:     "",
 		expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "GET-INSTALL-PATH-IN-0-1"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
 	}, {
 		description:  "tidy only environment variable specified",
 		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
@@ -1156,10 +968,6 @@
 		curDir:       "0/1/2",
 		tidyOnly:     "1",
 		expectedArgs: []string{"tidy_only"},
-		expectedEnvVars: []envVar{
-			envVar{
-				name:  "ONE_SHOT_MAKEFILE",
-				value: ""}},
 	}, {
 		description:  "normal execution from top dir directory",
 		dirsInTrees:  []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
@@ -1169,10 +977,6 @@
 		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"},
@@ -1182,14 +986,10 @@
 		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: ""}},
 	}}
 	for _, tt := range tests {
 		t.Run("build action BUILD_MODULES_IN_DIRS, "+tt.description, func(t *testing.T) {
-			testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES, true)
+			testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES)
 		})
 	}
 }
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 5ad966a..9ddbbea 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -42,9 +42,6 @@
 	if args := config.KatiArgs(); len(args) > 0 {
 		katiSuffix += "-" + spaceSlashReplacer.Replace(strings.Join(args, "_"))
 	}
-	if oneShot, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
-		katiSuffix += "-" + spaceSlashReplacer.Replace(oneShot)
-	}
 
 	// If the suffix is too long, replace it with a md5 hash and write a
 	// file that contains the original suffix.
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index b169666..100cc65 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -79,13 +79,11 @@
 	"dd":       Allowed,
 	"diff":     Allowed,
 	"dlv":      Allowed,
-	"egrep":    Allowed,
 	"expr":     Allowed,
 	"find":     Allowed,
 	"fuser":    Allowed,
 	"getopt":   Allowed,
 	"git":      Allowed,
-	"grep":     Allowed,
 	"gzcat":    Allowed,
 	"gzip":     Allowed,
 	"hexdump":  Allowed,
@@ -132,9 +130,11 @@
 	"dirname":   LinuxOnlyPrebuilt,
 	"du":        LinuxOnlyPrebuilt,
 	"echo":      LinuxOnlyPrebuilt,
+	"egrep":     LinuxOnlyPrebuilt,
 	"env":       LinuxOnlyPrebuilt,
-	"head":      LinuxOnlyPrebuilt,
 	"getconf":   LinuxOnlyPrebuilt,
+	"grep":      LinuxOnlyPrebuilt,
+	"head":      LinuxOnlyPrebuilt,
 	"hostname":  LinuxOnlyPrebuilt,
 	"id":        LinuxOnlyPrebuilt,
 	"ln":        LinuxOnlyPrebuilt,
diff --git a/ui/terminal/smart_status.go b/ui/terminal/smart_status.go
index 8659d4d..57f71ab 100644
--- a/ui/terminal/smart_status.go
+++ b/ui/terminal/smart_status.go
@@ -59,21 +59,24 @@
 // current build status similarly to Ninja's built-in terminal
 // output.
 func NewSmartStatusOutput(w io.Writer, formatter formatter) status.StatusOutput {
-	tableHeight, _ := strconv.Atoi(os.Getenv(tableHeightEnVar))
-
 	s := &smartStatusOutput{
 		writer:    w,
 		formatter: formatter,
 
 		haveBlankLine: true,
 
-		tableMode:            tableHeight > 0,
-		requestedTableHeight: tableHeight,
+		tableMode: true,
 
 		done:     make(chan bool),
 		sigwinch: make(chan os.Signal),
 	}
 
+	if env, ok := os.LookupEnv(tableHeightEnVar); ok {
+		h, _ := strconv.Atoi(env)
+		s.tableMode = h > 0
+		s.requestedTableHeight = h
+	}
+
 	s.updateTermSize()
 
 	if s.tableMode {
@@ -297,6 +300,14 @@
 
 		if s.tableMode {
 			tableHeight := s.requestedTableHeight
+			if tableHeight == 0 {
+				tableHeight = s.termHeight / 4
+				if tableHeight < 1 {
+					tableHeight = 1
+				} else if tableHeight > 10 {
+					tableHeight = 10
+				}
+			}
 			if tableHeight > s.termHeight-1 {
 				tableHeight = s.termHeight - 1
 			}