Optionally embed NOTICE files in apks.
am: 5b425e2e20

Change-Id: I0397838781d5ce7ba20778706d3b0ee4936080e8
diff --git a/apex/apex.go b/apex/apex.go
index 1dfd6dc..70a0bc5 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -145,7 +145,7 @@
 
 	android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.TopDown("apex_deps", apexDepsMutator)
-		ctx.BottomUp("apex", apexMutator)
+		ctx.BottomUp("apex", apexMutator).Parallel()
 	})
 }
 
diff --git a/cc/cc.go b/cc/cc.go
index 53ec899..1100bac 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -65,7 +65,7 @@
 		ctx.TopDown("tsan_deps", sanitizerDepsMutator(tsan))
 		ctx.BottomUp("tsan", sanitizerMutator(tsan)).Parallel()
 
-		ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator)
+		ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator).Parallel()
 		ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
 
 		ctx.BottomUp("coverage", coverageMutator).Parallel()
diff --git a/cc/gen.go b/cc/gen.go
index 1d30dab..c9f45ee 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -25,6 +25,7 @@
 
 func init() {
 	pctx.SourcePathVariable("lexCmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/flex")
+	pctx.SourcePathVariable("m4Cmd", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/m4")
 
 	pctx.HostBinToolVariable("aidlCmd", "aidl-cpp")
 	pctx.HostBinToolVariable("syspropCmd", "sysprop_cpp")
@@ -33,8 +34,8 @@
 var (
 	lex = pctx.AndroidStaticRule("lex",
 		blueprint.RuleParams{
-			Command:     "$lexCmd -o$out $in",
-			CommandDeps: []string{"$lexCmd"},
+			Command:     "M4=$m4Cmd $lexCmd -o$out $in",
+			CommandDeps: []string{"$lexCmd", "$m4Cmd"},
 		})
 
 	sysprop = pctx.AndroidStaticRule("sysprop",
diff --git a/cc/makevars.go b/cc/makevars.go
index a71f479..78a32c8 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -161,6 +161,8 @@
 
 	ctx.Strict("AIDL_CPP", "${aidlCmd}")
 
+	ctx.Strict("M4", "${m4Cmd}")
+
 	ctx.Strict("RS_GLOBAL_INCLUDES", "${config.RsGlobalIncludes}")
 
 	ctx.Strict("SOONG_STRIP_PATH", "${stripPath}")
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 0af0659..0eb9a74 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -468,6 +468,10 @@
 		// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
 		_, flags.LdFlags = removeFromList("-flto", flags.LdFlags)
 		flags.LdFlags = append(flags.LdFlags, "-fno-lto")
+
+		// TODO(b/133876586): Experimental PM breaks sanitizer coverage.
+		_, flags.CFlags = removeFromList("-fexperimental-new-pass-manager", flags.CFlags)
+		flags.CFlags = append(flags.CFlags, "-fno-experimental-new-pass-manager")
 	}
 
 	if Bool(sanitize.Properties.Sanitize.Cfi) {
@@ -701,8 +705,8 @@
 			if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
 				return false
 			}
-			if d, ok := child.(*Module); ok && d.static() && d.sanitize != nil {
 
+			if d, ok := child.(*Module); ok && d.static() && d.sanitize != nil {
 				if enableMinimalRuntime(d.sanitize) {
 					// If a static dependency is built with the minimal runtime,
 					// make sure we include the ubsan minimal runtime.
@@ -713,8 +717,17 @@
 					// make sure we include the ubsan runtime.
 					c.sanitize.Properties.UbsanRuntimeDep = true
 				}
+
+				if c.sanitize.Properties.MinimalRuntimeDep &&
+					c.sanitize.Properties.UbsanRuntimeDep {
+					// both flags that this mutator might set are true, so don't bother recursing
+					return false
+				}
+
+				return true
+			} else {
+				return false
 			}
-			return true
 		})
 	}
 }
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index b909779..d3ef415 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -161,6 +161,7 @@
 	trace.SetOutput(filepath.Join(logsDir, "build.trace"))
 	stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, "verbose.log")))
 	stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, "error.log")))
+	stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, "build_error")))
 
 	defer met.Dump(filepath.Join(logsDir, "soong_metrics"))
 
@@ -337,7 +338,7 @@
 	}{{
 		name:              "all-modules",
 		description:       "Build action: build from the top of the source tree.",
-		action:            build.BUILD_MODULES_IN_A_DIRECTORY,
+		action:            build.BUILD_MODULES,
 		buildDependencies: true,
 	}, {
 		name:              "modules-in-a-dir-no-deps",
diff --git a/finder/finder_test.go b/finder/finder_test.go
index 29711fc..f6d0aa9 100644
--- a/finder/finder_test.go
+++ b/finder/finder_test.go
@@ -891,8 +891,8 @@
 			IncludeFiles: []string{"findme.txt"},
 		},
 	)
-	foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
 	finder.Shutdown()
 	// check the response of the first finder
 	assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
@@ -1522,8 +1522,8 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
-	foundPaths := finder.FindAll()
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindAll()
 	finder.Shutdown()
 	// check results
 	assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
@@ -1583,8 +1583,8 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
-	foundPaths := finder.FindAll()
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindAll()
 	finder.Shutdown()
 	allPaths := []string{"/tmp/hi.txt", "/tmp/a/hi.txt", "/tmp/a/a/hi.txt", "/tmp/b/hi.txt"}
 	// check results
@@ -1629,8 +1629,8 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
-	foundPaths := finder.FindAll()
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindAll()
 	finder.Shutdown()
 	// check results
 	assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
@@ -1650,8 +1650,8 @@
 			IncludeFiles: []string{"hi.txt"},
 		},
 	)
-	foundPaths := finder.FindAll()
 	filesystem.Clock.Tick()
+	foundPaths := finder.FindAll()
 	finder.Shutdown()
 	// check results
 	assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
diff --git a/java/aapt2.go b/java/aapt2.go
index a815160..ad746f7 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -60,7 +60,9 @@
 	},
 	"outDir", "cFlags")
 
-func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths) android.WritablePaths {
+func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths,
+	flags []string) android.WritablePaths {
+
 	shards := shardPaths(paths, AAPT2_SHARD_SIZE)
 
 	ret := make(android.WritablePaths, 0, len(paths))
@@ -81,9 +83,7 @@
 			Outputs:     outPaths,
 			Args: map[string]string{
 				"outDir": android.PathForModuleOut(ctx, "aapt2", dir.String()).String(),
-				// Always set --pseudo-localize, it will be stripped out later for release
-				// builds that don't want it.
-				"cFlags": "--pseudo-localize",
+				"cFlags": strings.Join(flags, " "),
 			},
 		})
 	}
@@ -104,7 +104,9 @@
 		},
 	}, "cFlags", "resZipDir", "zipSyncFlags")
 
-func aapt2CompileZip(ctx android.ModuleContext, flata android.WritablePath, zip android.Path, zipPrefix string) {
+func aapt2CompileZip(ctx android.ModuleContext, flata android.WritablePath, zip android.Path, zipPrefix string,
+	flags []string) {
+
 	if zipPrefix != "" {
 		zipPrefix = "--zip-prefix " + zipPrefix
 	}
@@ -114,9 +116,7 @@
 		Input:       zip,
 		Output:      flata,
 		Args: map[string]string{
-			// Always set --pseudo-localize, it will be stripped out later for release
-			// builds that don't want it.
-			"cFlags":       "--pseudo-localize",
+			"cFlags":       strings.Join(flags, " "),
 			"resZipDir":    android.PathForModuleOut(ctx, "aapt2", "reszip", flata.Base()).String(),
 			"zipSyncFlags": zipPrefix,
 		},
diff --git a/java/aar.go b/java/aar.go
index fc0e493..c9306de 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -113,8 +113,9 @@
 	return a.transitiveManifestPaths
 }
 
-func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext, manifestPath android.Path) (flags []string,
-	deps android.Paths, resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
+func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext,
+	manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths,
+	resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) {
 
 	hasVersionCode := false
 	hasVersionName := false
@@ -126,8 +127,6 @@
 		}
 	}
 
-	var linkFlags []string
-
 	// Flags specified in Android.bp
 	linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...)
 
@@ -138,8 +137,6 @@
 	resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res")
 	resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips)
 
-	var linkDeps android.Paths
-
 	// Glob directories into lists of paths
 	for _, dir := range resourceDirs {
 		resDirs = append(resDirs, globbedResourceDir{
@@ -193,7 +190,13 @@
 		linkFlags = append(linkFlags, "--version-name ", versionName)
 	}
 
-	return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resourceZips
+	linkFlags, compileFlags = android.FilterList(linkFlags, []string{"--legacy"})
+
+	// Always set --pseudo-localize, it will be stripped out later for release
+	// builds that don't want it.
+	compileFlags = append(compileFlags, "--pseudo-localize")
+
+	return compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resourceZips
 }
 
 func (a *aapt) deps(ctx android.BottomUpMutatorContext, sdkDep sdkDep) {
@@ -228,7 +231,7 @@
 		a.mergedManifestFile = manifestPath
 	}
 
-	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath)
+	compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, sdkContext, manifestPath)
 
 	rroDirs = append(rroDirs, staticRRODirs...)
 	linkFlags = append(linkFlags, libFlags...)
@@ -247,12 +250,12 @@
 
 	var compiledResDirs []android.Paths
 	for _, dir := range resDirs {
-		compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files).Paths())
+		compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths())
 	}
 
 	for i, zip := range resZips {
 		flata := android.PathForModuleOut(ctx, fmt.Sprintf("reszip.%d.flata", i))
-		aapt2CompileZip(ctx, flata, zip, "")
+		aapt2CompileZip(ctx, flata, zip, "", compileFlags)
 		compiledResDirs = append(compiledResDirs, android.Paths{flata})
 	}
 
@@ -281,7 +284,7 @@
 	}
 
 	for _, dir := range overlayDirs {
-		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+		compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths()...)
 	}
 
 	var splitPackages android.WritablePaths
@@ -521,10 +524,6 @@
 	return a.sdkVersion()
 }
 
-func (a *AARImport) noFrameworkLibs() bool {
-	return false
-}
-
 var _ AndroidLibraryDependency = (*AARImport)(nil)
 
 func (a *AARImport) ExportPackage() android.Path {
@@ -606,9 +605,12 @@
 		},
 	})
 
+	// Always set --pseudo-localize, it will be stripped out later for release
+	// builds that don't want it.
+	compileFlags := []string{"--pseudo-localize"}
 	compiledResDir := android.PathForModuleOut(ctx, "flat-res")
 	flata := compiledResDir.Join(ctx, "gen_res.flata")
-	aapt2CompileZip(ctx, flata, aar, "res")
+	aapt2CompileZip(ctx, flata, aar, "res", compileFlags)
 
 	a.exportPackage = android.PathForModuleOut(ctx, "package-res.apk")
 	srcJar := android.PathForModuleGen(ctx, "R.jar")
diff --git a/java/app_test.go b/java/app_test.go
index 06f48fa..2e6d29a 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -546,79 +546,6 @@
 	}
 }
 
-func TestJNIABI_no_framework_libs_true(t *testing.T) {
-	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
-		cc_library {
-			name: "libjni",
-			system_shared_libs: [],
-			stl: "none",
-		}
-
-		android_test {
-			name: "test",
-			no_framework_libs: true,
-			jni_libs: ["libjni"],
-		}
-
-		android_test {
-			name: "test_first",
-			no_framework_libs: true,
-			compile_multilib: "first",
-			jni_libs: ["libjni"],
-		}
-
-		android_test {
-			name: "test_both",
-			no_framework_libs: true,
-			compile_multilib: "both",
-			jni_libs: ["libjni"],
-		}
-
-		android_test {
-			name: "test_32",
-			no_framework_libs: true,
-			compile_multilib: "32",
-			jni_libs: ["libjni"],
-		}
-
-		android_test {
-			name: "test_64",
-			no_framework_libs: true,
-			compile_multilib: "64",
-			jni_libs: ["libjni"],
-		}
-		`)
-
-	testCases := []struct {
-		name string
-		abis []string
-	}{
-		{"test", []string{"arm64-v8a"}},
-		{"test_first", []string{"arm64-v8a"}},
-		{"test_both", []string{"arm64-v8a", "armeabi-v7a"}},
-		{"test_32", []string{"armeabi-v7a"}},
-		{"test_64", []string{"arm64-v8a"}},
-	}
-
-	for _, test := range testCases {
-		t.Run(test.name, func(t *testing.T) {
-			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.Output("jnilibs.zip")
-			var abis []string
-			args := strings.Fields(jniLibZip.Args["jarArgs"])
-			for i := 0; i < len(args); i++ {
-				if args[i] == "-P" {
-					abis = append(abis, filepath.Base(args[i+1]))
-					i++
-				}
-			}
-			if !reflect.DeepEqual(abis, test.abis) {
-				t.Errorf("want abis %v, got %v", test.abis, abis)
-			}
-		})
-	}
-}
-
 func TestJNIABI(t *testing.T) {
 	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
@@ -692,89 +619,6 @@
 	}
 }
 
-func TestJNIPackaging_no_framework_libs_true(t *testing.T) {
-	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
-		cc_library {
-			name: "libjni",
-			system_shared_libs: [],
-			stl: "none",
-		}
-
-		android_app {
-			name: "app",
-			jni_libs: ["libjni"],
-		}
-
-		android_app {
-			name: "app_noembed",
-			jni_libs: ["libjni"],
-			use_embedded_native_libs: false,
-		}
-
-		android_app {
-			name: "app_embed",
-			jni_libs: ["libjni"],
-			use_embedded_native_libs: true,
-		}
-
-		android_test {
-			name: "test",
-			no_framework_libs: true,
-			jni_libs: ["libjni"],
-		}
-
-		android_test {
-			name: "test_noembed",
-			no_framework_libs: true,
-			jni_libs: ["libjni"],
-			use_embedded_native_libs: false,
-		}
-
-		android_test_helper_app {
-			name: "test_helper",
-			no_framework_libs: true,
-			jni_libs: ["libjni"],
-		}
-
-		android_test_helper_app {
-			name: "test_helper_noembed",
-			no_framework_libs: true,
-			jni_libs: ["libjni"],
-			use_embedded_native_libs: false,
-		}
-		`)
-
-	testCases := []struct {
-		name       string
-		packaged   bool
-		compressed bool
-	}{
-		{"app", false, false},
-		{"app_noembed", false, false},
-		{"app_embed", true, false},
-		{"test", true, false},
-		{"test_noembed", true, true},
-		{"test_helper", true, false},
-		{"test_helper_noembed", true, true},
-	}
-
-	for _, test := range testCases {
-		t.Run(test.name, func(t *testing.T) {
-			app := ctx.ModuleForTests(test.name, "android_common")
-			jniLibZip := app.MaybeOutput("jnilibs.zip")
-			if g, w := (jniLibZip.Rule != nil), test.packaged; g != w {
-				t.Errorf("expected jni packaged %v, got %v", w, g)
-			}
-
-			if jniLibZip.Rule != nil {
-				if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w {
-					t.Errorf("expected jni compressed %v, got %v", w, g)
-				}
-			}
-		})
-	}
-}
-
 func TestJNIPackaging(t *testing.T) {
 	ctx := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		cc_library {
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
index 146bf6f..9b9d0d8 100644
--- a/java/device_host_converter_test.go
+++ b/java/device_host_converter_test.go
@@ -126,7 +126,7 @@
 
 		java_library {
 			name: "device_module",
-			no_framework_libs: true,
+			sdk_version: "core_platform",
 			srcs: ["b.java"],
 			java_resources: ["java-res/b/b"],
 			static_libs: ["host_for_device_module"],
diff --git a/java/droiddoc.go b/java/droiddoc.go
index be1b281..734b411 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -171,9 +171,6 @@
 	// list of java libraries that will be in the classpath.
 	Libs []string `android:"arch_variant"`
 
-	// don't build against the framework libraries (ext, and framework for device targets)
-	No_framework_libs *bool
-
 	// the java library (in classpath) for documentation that provides java srcs and srcjars.
 	Srcs_lib *string
 
@@ -534,10 +531,6 @@
 	return j.sdkVersion()
 }
 
-func (j *Javadoc) noFrameworkLibs() bool {
-	return Bool(j.properties.No_framework_libs)
-}
-
 func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		sdkDep := decodeSdkDep(ctx, sdkContext(j))
diff --git a/java/java.go b/java/java.go
index a2e9ab0..bf80ced 100644
--- a/java/java.go
+++ b/java/java.go
@@ -82,9 +82,6 @@
 	// list of files that should be excluded from java_resources and java_resource_dirs
 	Exclude_java_resources []string `android:"path,arch_variant"`
 
-	// don't build against the framework libraries (ext, and framework for device targets)
-	No_framework_libs *bool
-
 	// list of module-specific flags that will be used for javac compiles
 	Javacflags []string `android:"arch_variant"`
 
@@ -482,10 +479,6 @@
 	return j.sdkVersion()
 }
 
-func (j *Module) noFrameworkLibs() bool {
-	return Bool(j.properties.No_framework_libs)
-}
-
 func (j *Module) deps(ctx android.BottomUpMutatorContext) {
 	if ctx.Device() {
 		sdkDep := decodeSdkDep(ctx, sdkContext(j))
@@ -506,7 +499,7 @@
 			}
 		} else if j.deviceProperties.System_modules == nil {
 			ctx.PropertyErrorf("sdk_version",
-				`system_modules is required to be set when sdk_version is "none", did you mean no_framework_libs?`)
+				`system_modules is required to be set when sdk_version is "none", did you mean "core_platform"`)
 		} else if *j.deviceProperties.System_modules != "none" {
 			ctx.AddVariationDependencies(nil, systemModulesTag, *j.deviceProperties.System_modules)
 		}
diff --git a/java/sdk.go b/java/sdk.go
index 6ffe399..1682a10 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -44,9 +44,6 @@
 	minSdkVersion() string
 	// targetSdkVersion returns the target_sdk_version property of the current module, or sdkVersion() if it is not set.
 	targetSdkVersion() string
-
-	// Temporarily provide access to the no_frameworks_libs property (where present).
-	noFrameworkLibs() bool
 }
 
 func sdkVersionOrDefault(ctx android.BaseModuleContext, v string) string {
@@ -84,6 +81,7 @@
 
 func decodeSdkDep(ctx android.BaseModuleContext, sdkContext sdkContext) sdkDep {
 	v := sdkContext.sdkVersion()
+
 	// For PDK builds, use the latest SDK version instead of "current"
 	if ctx.Config().IsPdkBuild() && (v == "" || v == "current") {
 		sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
@@ -141,9 +139,6 @@
 			useFiles: true,
 			jars:     android.Paths{jarPath.Path(), lambdaStubsPath},
 			aidl:     android.OptionalPathForPath(aidlPath.Path()),
-
-			// Pass value straight through for now to match previous behavior.
-			noFrameworksLibs: sdkContext.noFrameworkLibs(),
 		}
 	}
 
@@ -154,9 +149,6 @@
 			systemModules:      m + "_system_modules",
 			frameworkResModule: r,
 			aidl:               android.OptionalPathForPath(aidl),
-
-			// Pass value straight through for now to match previous behavior.
-			noFrameworksLibs: sdkContext.noFrameworkLibs(),
 		}
 
 		if m == "core.current.stubs" {
@@ -192,9 +184,6 @@
 		return sdkDep{
 			useDefaultLibs:     true,
 			frameworkResModule: "framework-res",
-
-			// Pass value straight through for now to match previous behavior.
-			noFrameworksLibs: sdkContext.noFrameworkLibs(),
 		}
 	case "none":
 		return sdkDep{
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 953c372..f82a4fb 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -47,14 +47,6 @@
 			aidl:          "-Iframework/aidl",
 		},
 		{
-			name:          "no_framework_libs:true",
-			properties:    `no_framework_libs:true`,
-			bootclasspath: config.DefaultBootclasspathLibraries,
-			system:        config.DefaultSystemModules,
-			classpath:     []string{},
-			aidl:          "",
-		},
-		{
 			name:          `sdk_version:"core_platform"`,
 			properties:    `sdk_version:"core_platform"`,
 			bootclasspath: config.DefaultBootclasspathLibraries,
diff --git a/java/system_modules.go b/java/system_modules.go
index f71f452..c616249 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -138,7 +138,7 @@
 			fmt.Fprintln(w, makevar, ":=$=", strings.Join(system.properties.Libs, " "))
 			fmt.Fprintln(w)
 
-			makevar = "SOONG_SYSTEM_MODULE_DEPS_" + name
+			makevar = "SOONG_SYSTEM_MODULES_DEPS_" + name
 			fmt.Fprintln(w, makevar, ":=$=", strings.Join(system.outputDeps.Strings(), " "))
 			fmt.Fprintln(w)
 
diff --git a/ui/build/config.go b/ui/build/config.go
index 6df9529..4a70f06 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -71,6 +71,9 @@
 	// Builds all of the modules and their dependencies of a list of specified directories. All specified
 	// directories are relative to the root directory of the source tree.
 	BUILD_MODULES_IN_DIRECTORIES
+
+	// Build a list of specified modules. If none was specified, simply build the whole source tree.
+	BUILD_MODULES
 )
 
 // checkTopDir validates that the current directory is at the root directory of the source tree.
@@ -290,6 +293,8 @@
 	var targets []string
 
 	switch action {
+	case BUILD_MODULES:
+		// No additional processing is required when building a list of specific modules or all modules.
 	case BUILD_MODULES_IN_A_DIRECTORY:
 		// If dir is the root source tree, all the modules are built of the source tree are built so
 		// no need to find the build file.
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 1ef5456..856af11 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -763,6 +763,51 @@
 	}
 }
 
+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 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, 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 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:          "1/2/3/4/5/6/7/8/9",
+		tidyOnly:        "",
+		expectedArgs:    []string{},
+		expectedEnvVars: []envVar{},
+	}}
+	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{{
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index c9946e2..e2c5043 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -88,13 +88,14 @@
 	"getopt":   Allowed,
 	"git":      Allowed,
 	"grep":     Allowed,
+	"gzcat":    Allowed,
 	"gzip":     Allowed,
 	"hexdump":  Allowed,
 	"jar":      Allowed,
 	"java":     Allowed,
 	"javap":    Allowed,
 	"lsof":     Allowed,
-	"m4":       Allowed,
+	"m4":       Log,
 	"openssl":  Allowed,
 	"patch":    Allowed,
 	"pstree":   Allowed,
diff --git a/ui/status/Android.bp b/ui/status/Android.bp
index 901a713..34241ee 100644
--- a/ui/status/Android.bp
+++ b/ui/status/Android.bp
@@ -19,6 +19,7 @@
         "golang-protobuf-proto",
         "soong-ui-logger",
         "soong-ui-status-ninja_frontend",
+        "soong-ui-status-build_error_proto",
     ],
     srcs: [
         "kati.go",
@@ -41,3 +42,12 @@
         "ninja_frontend/frontend.pb.go",
     ],
 }
+
+bootstrap_go_package {
+    name: "soong-ui-status-build_error_proto",
+    pkgPath: "android/soong/ui/status/build_error_proto",
+    deps: ["golang-protobuf-proto"],
+    srcs: [
+        "build_error_proto/build_error.pb.go",
+    ],
+}
diff --git a/ui/status/build_error_proto/build_error.pb.go b/ui/status/build_error_proto/build_error.pb.go
new file mode 100644
index 0000000..d4d0a6e
--- /dev/null
+++ b/ui/status/build_error_proto/build_error.pb.go
@@ -0,0 +1,175 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: build_error.proto
+
+package soong_build_error_proto
+
+import (
+	fmt "fmt"
+	proto "github.com/golang/protobuf/proto"
+	math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type BuildError struct {
+	// List of error messages of the overall build. The error messages
+	// are not associated with a build action.
+	ErrorMessages []string `protobuf:"bytes,1,rep,name=error_messages,json=errorMessages" json:"error_messages,omitempty"`
+	// List of build action errors.
+	ActionErrors         []*BuildActionError `protobuf:"bytes,2,rep,name=action_errors,json=actionErrors" json:"action_errors,omitempty"`
+	XXX_NoUnkeyedLiteral struct{}            `json:"-"`
+	XXX_unrecognized     []byte              `json:"-"`
+	XXX_sizecache        int32               `json:"-"`
+}
+
+func (m *BuildError) Reset()         { *m = BuildError{} }
+func (m *BuildError) String() string { return proto.CompactTextString(m) }
+func (*BuildError) ProtoMessage()    {}
+func (*BuildError) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a2e15b05802a5501, []int{0}
+}
+
+func (m *BuildError) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_BuildError.Unmarshal(m, b)
+}
+func (m *BuildError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_BuildError.Marshal(b, m, deterministic)
+}
+func (m *BuildError) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_BuildError.Merge(m, src)
+}
+func (m *BuildError) XXX_Size() int {
+	return xxx_messageInfo_BuildError.Size(m)
+}
+func (m *BuildError) XXX_DiscardUnknown() {
+	xxx_messageInfo_BuildError.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BuildError proto.InternalMessageInfo
+
+func (m *BuildError) GetErrorMessages() []string {
+	if m != nil {
+		return m.ErrorMessages
+	}
+	return nil
+}
+
+func (m *BuildError) GetActionErrors() []*BuildActionError {
+	if m != nil {
+		return m.ActionErrors
+	}
+	return nil
+}
+
+// Build is composed of a list of build action. There can be a set of build
+// actions that can failed.
+type BuildActionError struct {
+	// Description of the command.
+	Description *string `protobuf:"bytes,1,opt,name=description" json:"description,omitempty"`
+	// The command name that raised the error.
+	Command *string `protobuf:"bytes,2,opt,name=command" json:"command,omitempty"`
+	// The command output stream.
+	Output *string `protobuf:"bytes,3,opt,name=output" json:"output,omitempty"`
+	// List of artifacts (i.e. files) that was produced by the command.
+	Artifacts []string `protobuf:"bytes,4,rep,name=artifacts" json:"artifacts,omitempty"`
+	// The error string produced by the build action.
+	Error                *string  `protobuf:"bytes,5,opt,name=error" json:"error,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *BuildActionError) Reset()         { *m = BuildActionError{} }
+func (m *BuildActionError) String() string { return proto.CompactTextString(m) }
+func (*BuildActionError) ProtoMessage()    {}
+func (*BuildActionError) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a2e15b05802a5501, []int{1}
+}
+
+func (m *BuildActionError) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_BuildActionError.Unmarshal(m, b)
+}
+func (m *BuildActionError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_BuildActionError.Marshal(b, m, deterministic)
+}
+func (m *BuildActionError) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_BuildActionError.Merge(m, src)
+}
+func (m *BuildActionError) XXX_Size() int {
+	return xxx_messageInfo_BuildActionError.Size(m)
+}
+func (m *BuildActionError) XXX_DiscardUnknown() {
+	xxx_messageInfo_BuildActionError.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BuildActionError proto.InternalMessageInfo
+
+func (m *BuildActionError) GetDescription() string {
+	if m != nil && m.Description != nil {
+		return *m.Description
+	}
+	return ""
+}
+
+func (m *BuildActionError) GetCommand() string {
+	if m != nil && m.Command != nil {
+		return *m.Command
+	}
+	return ""
+}
+
+func (m *BuildActionError) GetOutput() string {
+	if m != nil && m.Output != nil {
+		return *m.Output
+	}
+	return ""
+}
+
+func (m *BuildActionError) GetArtifacts() []string {
+	if m != nil {
+		return m.Artifacts
+	}
+	return nil
+}
+
+func (m *BuildActionError) GetError() string {
+	if m != nil && m.Error != nil {
+		return *m.Error
+	}
+	return ""
+}
+
+func init() {
+	proto.RegisterType((*BuildError)(nil), "soong_build_error.BuildError")
+	proto.RegisterType((*BuildActionError)(nil), "soong_build_error.BuildActionError")
+}
+
+func init() { proto.RegisterFile("build_error.proto", fileDescriptor_a2e15b05802a5501) }
+
+var fileDescriptor_a2e15b05802a5501 = []byte{
+	// 229 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x64, 0x90, 0xc1, 0x4a, 0xc3, 0x40,
+	0x10, 0x86, 0x49, 0x63, 0x95, 0x4c, 0xad, 0xd8, 0x41, 0x74, 0x04, 0x0f, 0xa1, 0x22, 0xe4, 0x94,
+	0x83, 0x6f, 0x60, 0x41, 0xf0, 0xe2, 0x25, 0x47, 0x2f, 0x61, 0xdd, 0xac, 0x65, 0xc1, 0x64, 0xc2,
+	0xce, 0xe6, 0xe8, 0x8b, 0xf8, 0xb4, 0x92, 0x69, 0xa5, 0xa5, 0x39, 0x7e, 0xdf, 0x3f, 0xfb, 0xef,
+	0xce, 0xc2, 0xea, 0x73, 0xf0, 0xdf, 0x4d, 0xed, 0x42, 0xe0, 0x50, 0xf6, 0x81, 0x23, 0xe3, 0x4a,
+	0x98, 0xbb, 0x6d, 0x7d, 0x14, 0xac, 0x7f, 0x00, 0x36, 0x23, 0xbe, 0x8e, 0x84, 0x4f, 0x70, 0xa5,
+	0xba, 0x6e, 0x9d, 0x88, 0xd9, 0x3a, 0xa1, 0x24, 0x4f, 0x8b, 0xac, 0x5a, 0xaa, 0x7d, 0xdf, 0x4b,
+	0x7c, 0x83, 0xa5, 0xb1, 0xd1, 0x73, 0xb7, 0x2b, 0x11, 0x9a, 0xe5, 0x69, 0xb1, 0x78, 0x7e, 0x2c,
+	0x27, 0xfd, 0xa5, 0x96, 0xbf, 0xe8, 0xb0, 0x5e, 0x51, 0x5d, 0x9a, 0x03, 0xc8, 0xfa, 0x37, 0x81,
+	0xeb, 0xd3, 0x11, 0xcc, 0x61, 0xd1, 0x38, 0xb1, 0xc1, 0xf7, 0xa3, 0xa3, 0x24, 0x4f, 0x8a, 0xac,
+	0x3a, 0x56, 0x48, 0x70, 0x61, 0xb9, 0x6d, 0x4d, 0xd7, 0xd0, 0x4c, 0xd3, 0x7f, 0xc4, 0x5b, 0x38,
+	0xe7, 0x21, 0xf6, 0x43, 0xa4, 0x54, 0x83, 0x3d, 0xe1, 0x03, 0x64, 0x26, 0x44, 0xff, 0x65, 0x6c,
+	0x14, 0x3a, 0xd3, 0xa5, 0x0e, 0x02, 0x6f, 0x60, 0xae, 0xcf, 0xa5, 0xb9, 0x1e, 0xda, 0xc1, 0xe6,
+	0xfe, 0xe3, 0x6e, 0xb2, 0x50, 0xad, 0x3f, 0xf9, 0x17, 0x00, 0x00, 0xff, 0xff, 0xb6, 0x18, 0x9e,
+	0x17, 0x5d, 0x01, 0x00, 0x00,
+}
diff --git a/ui/status/build_error_proto/build_error.proto b/ui/status/build_error_proto/build_error.proto
new file mode 100644
index 0000000..9c8470d
--- /dev/null
+++ b/ui/status/build_error_proto/build_error.proto
@@ -0,0 +1,46 @@
+// Copyright 2019 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+
+package soong_build_error;
+option go_package = "soong_build_error_proto";
+
+message BuildError {
+  // List of error messages of the overall build. The error messages
+  // are not associated with a build action.
+  repeated string error_messages = 1;
+
+  // List of build action errors.
+  repeated BuildActionError action_errors = 2;
+}
+
+// Build is composed of a list of build action. There can be a set of build
+// actions that can failed.
+message BuildActionError {
+  // Description of the command.
+  optional string description = 1;
+
+  // The command name that raised the error.
+  optional string command = 2;
+
+  // The command output stream.
+  optional string output = 3;
+
+  // List of artifacts (i.e. files) that was produced by the command.
+  repeated string artifacts = 4;
+
+  // The error string produced by the build action.
+  optional string error = 5;
+}
diff --git a/ui/status/build_error_proto/regen.sh b/ui/status/build_error_proto/regen.sh
new file mode 100755
index 0000000..7c3ec8f
--- /dev/null
+++ b/ui/status/build_error_proto/regen.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+aprotoc --go_out=paths=source_relative:. build_error.proto
diff --git a/ui/status/log.go b/ui/status/log.go
index 7badac7..9090f49 100644
--- a/ui/status/log.go
+++ b/ui/status/log.go
@@ -15,11 +15,17 @@
 package status
 
 import (
-	"android/soong/ui/logger"
 	"compress/gzip"
+	"errors"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"strings"
+
+	"github.com/golang/protobuf/proto"
+
+	"android/soong/ui/logger"
+	"android/soong/ui/status/build_error_proto"
 )
 
 type verboseLog struct {
@@ -77,8 +83,7 @@
 }
 
 type errorLog struct {
-	w io.WriteCloser
-
+	w     io.WriteCloser
 	empty bool
 }
 
@@ -102,20 +107,17 @@
 		return
 	}
 
-	cmd := result.Command
-	if cmd == "" {
-		cmd = result.Description
-	}
-
 	if !e.empty {
 		fmt.Fprintf(e.w, "\n\n")
 	}
 	e.empty = false
 
 	fmt.Fprintf(e.w, "FAILED: %s\n", result.Description)
+
 	if len(result.Outputs) > 0 {
 		fmt.Fprintf(e.w, "Outputs: %s\n", strings.Join(result.Outputs, " "))
 	}
+
 	fmt.Fprintf(e.w, "Error: %s\n", result.Error)
 	if result.Command != "" {
 		fmt.Fprintf(e.w, "Command: %s\n", result.Command)
@@ -144,3 +146,55 @@
 	fmt.Fprint(e.w, string(p))
 	return len(p), nil
 }
+
+type errorProtoLog struct {
+	errorProto soong_build_error_proto.BuildError
+	filename   string
+	log        logger.Logger
+}
+
+func NewProtoErrorLog(log logger.Logger, filename string) StatusOutput {
+	return &errorProtoLog{
+		errorProto: soong_build_error_proto.BuildError{},
+		filename:   filename,
+		log:        log,
+	}
+}
+
+func (e *errorProtoLog) StartAction(action *Action, counts Counts) {}
+
+func (e *errorProtoLog) FinishAction(result ActionResult, counts Counts) {
+	if result.Error == nil {
+		return
+	}
+
+	e.errorProto.ActionErrors = append(e.errorProto.ActionErrors, &soong_build_error_proto.BuildActionError{
+		Description: proto.String(result.Description),
+		Command:     proto.String(result.Command),
+		Output:      proto.String(result.Output),
+		Artifacts:   result.Outputs,
+		Error:       proto.String(result.Error.Error()),
+	})
+}
+
+func (e *errorProtoLog) Flush() {
+	data, err := proto.Marshal(&e.errorProto)
+	if err != nil {
+		e.log.Println("Failed to marshal build status proto: %v", err)
+		return
+	}
+	err = ioutil.WriteFile(e.filename, []byte(data), 0644)
+	if err != nil {
+		e.log.Println("Failed to write file %s: %v", e.errorProto, err)
+	}
+}
+
+func (e *errorProtoLog) Message(level MsgLevel, message string) {
+	if level > ErrorLvl {
+		e.errorProto.ErrorMessages = append(e.errorProto.ErrorMessages, message)
+	}
+}
+
+func (e *errorProtoLog) Write(p []byte) (int, error) {
+	return 0, errors.New("not supported")
+}
diff --git a/ui/terminal/smart_status.go b/ui/terminal/smart_status.go
index 9638cdf..8659d4d 100644
--- a/ui/terminal/smart_status.go
+++ b/ui/terminal/smart_status.go
@@ -225,9 +225,7 @@
 
 	// Limit line width to the terminal width, otherwise we'll wrap onto
 	// another line and we won't delete the previous line.
-	if s.termWidth > 0 {
-		str = s.elide(str)
-	}
+	str = elide(str, s.termWidth)
 
 	// Move to the beginning on the line, turn on bold, print the output,
 	// turn off bold, then clear the rest of the line.
@@ -237,11 +235,11 @@
 	s.haveBlankLine = false
 }
 
-func (s *smartStatusOutput) elide(str string) string {
-	if len(str) > s.termWidth {
+func elide(str string, width int) string {
+	if width > 0 && len(str) > width {
 		// TODO: Just do a max. Ninja elides the middle, but that's
 		// more complicated and these lines aren't that important.
-		str = str[:s.termWidth]
+		str = str[:width]
 	}
 
 	return str
@@ -344,9 +342,18 @@
 			desc = runningAction.action.Command
 		}
 
-		str := fmt.Sprintf("   %2d:%02d %s", seconds/60, seconds%60, desc)
-		str = s.elide(str)
-		fmt.Fprint(s.writer, str, ansi.clearToEndOfLine())
+		color := ""
+		if seconds >= 60 {
+			color = ansi.red() + ansi.bold()
+		} else if seconds >= 30 {
+			color = ansi.yellow() + ansi.bold()
+		}
+
+		durationStr := fmt.Sprintf("   %2d:%02d ", seconds/60, seconds%60)
+		desc = elide(desc, s.termWidth-len(durationStr))
+		durationStr = color + durationStr + ansi.regular()
+
+		fmt.Fprint(s.writer, durationStr, desc, ansi.clearToEndOfLine())
 		if tableLine < s.tableHeight-1 {
 			fmt.Fprint(s.writer, "\n")
 		}
@@ -387,6 +394,14 @@
 	return fmt.Sprintf("\x1b[r")
 }
 
+func (ansiImpl) red() string {
+	return "\x1b[31m"
+}
+
+func (ansiImpl) yellow() string {
+	return "\x1b[33m"
+}
+
 func (ansiImpl) bold() string {
 	return "\x1b[1m"
 }