Merge "Revert "Enforce min_sdk_version of apex(use_vendor:true)""
diff --git a/android/config.go b/android/config.go
index bbbe3c8..7953170 100644
--- a/android/config.go
+++ b/android/config.go
@@ -872,6 +872,13 @@
 
 func (c *config) EnforceRROForModule(name string) bool {
 	enforceList := c.productVariables.EnforceRROTargets
+	// TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency.
+	exemptedList := c.productVariables.EnforceRROExemptedTargets
+	if exemptedList != nil {
+		if InList(name, exemptedList) {
+			return false
+		}
+	}
 	if enforceList != nil {
 		if InList("*", enforceList) {
 			return true
diff --git a/android/module.go b/android/module.go
index 2e33056..057a5c7 100644
--- a/android/module.go
+++ b/android/module.go
@@ -985,6 +985,16 @@
 	}
 }
 
+func (m *ModuleBase) getVariationByMutatorName(mutator string) string {
+	for i, v := range m.commonProperties.DebugMutators {
+		if v == mutator {
+			return m.commonProperties.DebugVariations[i]
+		}
+	}
+
+	return ""
+}
+
 func (m *ModuleBase) InRamdisk() bool {
 	return m.base().commonProperties.ImageVariation == RamdiskVariation
 }
diff --git a/android/prebuilt.go b/android/prebuilt.go
index 2d16f65..c902ec8 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -50,12 +50,9 @@
 
 type Prebuilt struct {
 	properties PrebuiltProperties
-	module     Module
-	srcs       *[]string
 
-	// Metadata for single source Prebuilt modules.
-	srcProps reflect.Value
-	srcField reflect.StructField
+	srcsSupplier     PrebuiltSrcsSupplier
+	srcsPropertyName string
 }
 
 func (p *Prebuilt) Name(name string) string {
@@ -72,31 +69,26 @@
 // preference configs. We'll want to add native support for dynamic source cases if we end up having
 // more modules like this.
 func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
-	if p.srcs != nil {
-		if len(*p.srcs) == 0 {
-			ctx.PropertyErrorf("srcs", "missing prebuilt source file")
+	if p.srcsSupplier != nil {
+		srcs := p.srcsSupplier()
+
+		if len(srcs) == 0 {
+			ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file")
 			return nil
 		}
 
-		if len(*p.srcs) > 1 {
-			ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+		if len(srcs) > 1 {
+			ctx.PropertyErrorf(p.srcsPropertyName, "multiple prebuilt source files")
 			return nil
 		}
 
 		// Return the singleton source after expanding any filegroup in the
 		// sources.
-		return PathForModuleSrc(ctx, (*p.srcs)[0])
-	} else {
-		if !p.srcProps.IsValid() {
-			ctx.ModuleErrorf("prebuilt source was not set")
-		}
-		src := p.getSingleSourceFieldValue()
-		if src == "" {
-			ctx.PropertyErrorf(proptools.FieldNameForProperty(p.srcField.Name),
-				"missing prebuilt source file")
-			return nil
-		}
+		src := srcs[0]
 		return PathForModuleSrc(ctx, src)
+	} else {
+		ctx.ModuleErrorf("prebuilt source was not set")
+		return nil
 	}
 }
 
@@ -104,18 +96,80 @@
 	return p.properties.UsePrebuilt
 }
 
-func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
+// Called to provide the srcs value for the prebuilt module.
+//
+// Return the src value or nil if it is not available.
+type PrebuiltSrcsSupplier func() []string
+
+// Initialize the module as a prebuilt module that uses the provided supplier to access the
+// prebuilt sources of the module.
+//
+// The supplier will be called multiple times and must return the same values each time it
+// is called. If it returns an empty array (or nil) then the prebuilt module will not be used
+// as a replacement for a source module with the same name even if prefer = true.
+//
+// If the Prebuilt.SingleSourcePath() is called on the module then this must return an array
+// containing exactly one source file.
+//
+// The provided property name is used to provide helpful error messages in the event that
+// a problem arises, e.g. calling SingleSourcePath() when more than one source is provided.
+func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) {
 	p := module.Prebuilt()
 	module.AddProperties(&p.properties)
-	p.srcs = srcs
+
+	if srcsSupplier == nil {
+		panic(fmt.Errorf("srcsSupplier must not be nil"))
+	}
+	if srcsPropertyName == "" {
+		panic(fmt.Errorf("srcsPropertyName must not be empty"))
+	}
+
+	p.srcsSupplier = srcsSupplier
+	p.srcsPropertyName = srcsPropertyName
+}
+
+func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
+	if srcs == nil {
+		panic(fmt.Errorf("srcs must not be nil"))
+	}
+
+	srcsSupplier := func() []string {
+		return *srcs
+	}
+
+	InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
 }
 
 func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
-	p := module.Prebuilt()
-	module.AddProperties(&p.properties)
-	p.srcProps = reflect.ValueOf(srcProps).Elem()
-	p.srcField, _ = p.srcProps.Type().FieldByName(srcField)
-	p.checkSingleSourceProperties()
+	srcPropsValue := reflect.ValueOf(srcProps).Elem()
+	srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
+	if !srcPropsValue.IsValid() || srcStructField.Name == "" {
+		panic(fmt.Errorf("invalid single source prebuilt %+v", module))
+	}
+
+	if srcPropsValue.Kind() != reflect.Struct && srcPropsValue.Kind() != reflect.Interface {
+		panic(fmt.Errorf("invalid single source prebuilt %+v", srcProps))
+	}
+
+	srcFieldIndex := srcStructField.Index
+	srcPropertyName := proptools.PropertyNameForField(srcField)
+
+	srcsSupplier := func() []string {
+		value := srcPropsValue.FieldByIndex(srcFieldIndex)
+		if value.Kind() == reflect.Ptr {
+			value = value.Elem()
+		}
+		if value.Kind() != reflect.String {
+			panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one but was %d %q", srcPropertyName, value.Kind(), value))
+		}
+		src := value.String()
+		if src == "" {
+			return nil
+		}
+		return []string{src}
+	}
+
+	InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcPropertyName)
 }
 
 type PrebuiltInterface interface {
@@ -152,7 +206,7 @@
 func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
 	if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
 		p := m.Prebuilt()
-		if p.srcs == nil && !p.srcProps.IsValid() {
+		if p.srcsSupplier == nil {
 			panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
 		}
 		if !p.properties.SourceExists {
@@ -191,11 +245,7 @@
 // usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
 // will be used if it is marked "prefer" or if the source module is disabled.
 func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
-	if p.srcs != nil && len(*p.srcs) == 0 {
-		return false
-	}
-
-	if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" {
+	if p.srcsSupplier != nil && len(p.srcsSupplier()) == 0 {
 		return false
 	}
 
@@ -210,24 +260,3 @@
 func (p *Prebuilt) SourceExists() bool {
 	return p.properties.SourceExists
 }
-
-func (p *Prebuilt) checkSingleSourceProperties() {
-	if !p.srcProps.IsValid() || p.srcField.Name == "" {
-		panic(fmt.Errorf("invalid single source prebuilt %+v", p))
-	}
-
-	if p.srcProps.Kind() != reflect.Struct && p.srcProps.Kind() != reflect.Interface {
-		panic(fmt.Errorf("invalid single source prebuilt %+v", p.srcProps))
-	}
-}
-
-func (p *Prebuilt) getSingleSourceFieldValue() string {
-	value := p.srcProps.FieldByIndex(p.srcField.Index)
-	if value.Kind() == reflect.Ptr {
-		value = value.Elem()
-	}
-	if value.Kind() != reflect.String {
-		panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one", p.srcField.Name))
-	}
-	return value.String()
-}
diff --git a/android/sdk.go b/android/sdk.go
index 5c7b329..731bdff 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -304,10 +304,11 @@
 	// SdkAware and be added with an SdkMemberTypeDependencyTag tag.
 	HasTransitiveSdkMembers() bool
 
-	// Add dependencies from the SDK module to all the variants the member
-	// contributes to the SDK. The exact set of variants required is determined
-	// by the SDK and its properties. The dependencies must be added with the
-	// supplied tag.
+	// Add dependencies from the SDK module to all the module variants the member
+	// type contributes to the SDK. `names` is the list of module names given in
+	// the member type property (as returned by SdkPropertyName()) in the SDK
+	// module. The exact set of variants required is determined by the SDK and its
+	// properties. The dependencies must be added with the supplied tag.
 	//
 	// The BottomUpMutatorContext provided is for the SDK module.
 	AddDependencies(mctx BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string)
diff --git a/android/variable.go b/android/variable.go
index 25c94bc..91de956 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -188,9 +188,11 @@
 	CrossHostArch          *string `json:",omitempty"`
 	CrossHostSecondaryArch *string `json:",omitempty"`
 
-	DeviceResourceOverlays     []string `json:",omitempty"`
-	ProductResourceOverlays    []string `json:",omitempty"`
-	EnforceRROTargets          []string `json:",omitempty"`
+	DeviceResourceOverlays  []string `json:",omitempty"`
+	ProductResourceOverlays []string `json:",omitempty"`
+	EnforceRROTargets       []string `json:",omitempty"`
+	// TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency.
+	EnforceRROExemptedTargets  []string `json:",omitempty"`
 	EnforceRROExcludedOverlays []string `json:",omitempty"`
 
 	AAPTCharacteristics *string  `json:",omitempty"`
diff --git a/apex/apex_test.go b/apex/apex_test.go
index babc27b..5468c77 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -168,6 +168,7 @@
 		"vendor/foo/devkeys/testkey.pem":             nil,
 		"NOTICE":                                     nil,
 		"custom_notice":                              nil,
+		"custom_notice_for_static_lib":               nil,
 		"testkey2.avbpubkey":                         nil,
 		"testkey2.pem":                               nil,
 		"myapex-arm64.apex":                          nil,
@@ -372,6 +373,20 @@
 			system_shared_libs: [],
 			stl: "none",
 			notice: "custom_notice",
+			static_libs: ["libstatic"],
+			// TODO: remove //apex_available:platform
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+		}
+
+		cc_library_static {
+			name: "libstatic",
+			srcs: ["mylib.cpp"],
+			system_shared_libs: [],
+			stl: "none",
+			notice: "custom_notice_for_static_lib",
 			// TODO: remove //apex_available:platform
 			apex_available: [
 				"//apex_available:platform",
@@ -470,11 +485,12 @@
 
 	mergeNoticesRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("mergeNoticesRule")
 	noticeInputs := mergeNoticesRule.Inputs.Strings()
-	if len(noticeInputs) != 2 {
-		t.Errorf("number of input notice files: expected = 2, actual = %q", len(noticeInputs))
+	if len(noticeInputs) != 3 {
+		t.Errorf("number of input notice files: expected = 3, actual = %q", len(noticeInputs))
 	}
 	ensureListContains(t, noticeInputs, "NOTICE")
 	ensureListContains(t, noticeInputs, "custom_notice")
+	ensureListContains(t, noticeInputs, "custom_notice_for_static_lib")
 
 	depsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("myapex-deps-info.txt").Args["content"], "\\n")
 	ensureListContains(t, depsInfo, "myjar <- myapex")
diff --git a/apex/builder.go b/apex/builder.go
index 40adfca..67bc206 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -228,19 +228,15 @@
 }
 
 func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
-	noticeFiles := []android.Path{}
-	for _, f := range a.filesInfo {
-		if f.module != nil {
-			notices := f.module.NoticeFiles()
-			if len(notices) > 0 {
-				noticeFiles = append(noticeFiles, notices...)
-			}
+	var noticeFiles android.Paths
+
+	a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+		if externalDep {
+			return
 		}
-	}
-	// append the notice file specified in the apex module itself
-	if len(a.NoticeFiles()) > 0 {
-		noticeFiles = append(noticeFiles, a.NoticeFiles()...)
-	}
+		notices := to.NoticeFiles()
+		noticeFiles = append(noticeFiles, notices...)
+	})
 
 	if len(noticeFiles) == 0 {
 		return android.NoticeOutputs{}
diff --git a/cc/cc.go b/cc/cc.go
index 61ae10a..037b99c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2433,8 +2433,13 @@
 
 			if c, ok := ccDep.(*Module); ok {
 				// Use base module name for snapshots when exporting to Makefile.
-				if c.isSnapshotPrebuilt() && !c.IsVndk() {
+				if c.isSnapshotPrebuilt() {
 					baseName := c.BaseModuleName()
+
+					if c.IsVndk() {
+						return baseName + ".vendor"
+					}
+
 					if vendorSuffixModules[baseName] {
 						return baseName + ".vendor"
 					} else {
diff --git a/cc/config/global.go b/cc/config/global.go
index d01dd84..29020ab 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -127,8 +127,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r377782b"
-	ClangDefaultShortVersion = "10.0.4"
+	ClangDefaultVersion      = "clang-r377782c"
+	ClangDefaultShortVersion = "10.0.5"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/library.go b/cc/library.go
index 335b18e..346e7d8 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -195,6 +195,7 @@
 	module.sdkMemberTypes = []android.SdkMemberType{
 		sharedLibrarySdkMemberType,
 		staticLibrarySdkMemberType,
+		staticAndSharedLibrarySdkMemberType,
 	}
 	return module.Init()
 }
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 88cf7af..b7ab390 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -29,7 +29,7 @@
 		SupportsSdk:  true,
 	},
 	prebuiltModuleType: "cc_prebuilt_library_headers",
-	linkTypes:          nil,
+	noOutputFiles:      true,
 }
 
 func RegisterLibraryHeadersBuildComponents(ctx android.RegistrationContext) {
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 843ebb0..d010db1 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -18,6 +18,7 @@
 	"path/filepath"
 
 	"android/soong/android"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
@@ -42,10 +43,20 @@
 	linkTypes:          []string{"static"},
 }
 
+var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{
+	SdkMemberTypeBase: android.SdkMemberTypeBase{
+		PropertyName: "native_libs",
+		SupportsSdk:  true,
+	},
+	prebuiltModuleType: "cc_prebuilt_library",
+	linkTypes:          []string{"static", "shared"},
+}
+
 func init() {
 	// Register sdk member types.
 	android.RegisterSdkMemberType(sharedLibrarySdkMemberType)
 	android.RegisterSdkMemberType(staticLibrarySdkMemberType)
+	android.RegisterSdkMemberType(staticAndSharedLibrarySdkMemberType)
 }
 
 type librarySdkMemberType struct {
@@ -53,7 +64,10 @@
 
 	prebuiltModuleType string
 
-	// The set of link types supported, set of "static", "shared".
+	noOutputFiles bool // True if there are no srcs files.
+
+	// The set of link types supported. A set of "static", "shared", or nil to
+	// skip link type variations.
 	linkTypes []string
 }
 
@@ -327,7 +341,7 @@
 
 	// If the library has some link types then it produces an output binary file, otherwise it
 	// is header only.
-	if p.memberType.linkTypes != nil {
+	if !p.memberType.noOutputFiles {
 		p.outputFile = ccModule.OutputFile().Path()
 	}
 
@@ -338,9 +352,12 @@
 
 	p.name = variant.Name()
 	p.archType = ccModule.Target().Arch.ArchType.String()
-	p.ExportedIncludeDirs = exportedIncludeDirs
-	p.exportedGeneratedIncludeDirs = exportedGeneratedIncludeDirs
-	p.ExportedSystemIncludeDirs = ccModule.ExportedSystemIncludeDirs()
+
+	// Make sure that the include directories are unique.
+	p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs)
+	p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs)
+	p.ExportedSystemIncludeDirs = android.FirstUniquePaths(ccModule.ExportedSystemIncludeDirs())
+
 	p.ExportedFlags = ccModule.ExportedFlags()
 	if ccModule.linker != nil {
 		specifiedDeps := specifiedDeps{}
diff --git a/cc/object.go b/cc/object.go
index ad31d09..19decec 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -26,6 +26,16 @@
 
 func init() {
 	android.RegisterModuleType("cc_object", ObjectFactory)
+	android.RegisterSdkMemberType(ccObjectSdkMemberType)
+}
+
+var ccObjectSdkMemberType = &librarySdkMemberType{
+	SdkMemberTypeBase: android.SdkMemberTypeBase{
+		PropertyName: "native_objects",
+		SupportsSdk:  true,
+	},
+	prebuiltModuleType: "cc_prebuilt_object",
+	linkTypes:          nil,
 }
 
 type objectLinker struct {
@@ -47,12 +57,18 @@
 	Linker_script *string `android:"path,arch_variant"`
 }
 
+func newObject() *Module {
+	module := newBaseModule(android.HostAndDeviceSupported, android.MultilibBoth)
+	module.sanitize = &sanitize{}
+	module.stl = &stl{}
+	return module
+}
+
 // cc_object runs the compiler without running the linker. It is rarely
 // necessary, but sometimes used to generate .s files from .c files to use as
 // input to a cc_genrule module.
 func ObjectFactory() android.Module {
-	module := newBaseModule(android.HostAndDeviceSupported, android.MultilibBoth)
-	module.sanitize = &sanitize{}
+	module := newObject()
 	module.linker = &objectLinker{
 		baseLinker: NewBaseLinker(module.sanitize),
 	}
@@ -61,7 +77,7 @@
 	// Clang's address-significance tables are incompatible with ld -r.
 	module.compiler.appendCflags([]string{"-fno-addrsig"})
 
-	module.stl = &stl{}
+	module.sdkMemberTypes = []android.SdkMemberType{ccObjectSdkMemberType}
 	return module.Init()
 }
 
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 2c18ac3..fc9cc17 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -23,8 +23,10 @@
 }
 
 func RegisterPrebuiltBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("cc_prebuilt_library", PrebuiltLibraryFactory)
 	ctx.RegisterModuleType("cc_prebuilt_library_shared", PrebuiltSharedLibraryFactory)
 	ctx.RegisterModuleType("cc_prebuilt_library_static", PrebuiltStaticLibraryFactory)
+	ctx.RegisterModuleType("cc_prebuilt_object", prebuiltObjectFactory)
 	ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory)
 }
 
@@ -96,10 +98,16 @@
 	p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
 
 	// TODO(ccross): verify shared library dependencies
-	if len(p.properties.Srcs) > 0 {
+	srcs := p.prebuiltSrcs()
+	if len(srcs) > 0 {
 		builderFlags := flagsToBuilderFlags(flags)
 
-		in := p.Prebuilt.SingleSourcePath(ctx)
+		if len(srcs) > 1 {
+			ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
+			return nil
+		}
+
+		in := android.PathForModuleSrc(ctx, srcs[0])
 
 		if p.shared() {
 			p.unstrippedOutputFile = in
@@ -123,6 +131,18 @@
 	return nil
 }
 
+func (p *prebuiltLibraryLinker) prebuiltSrcs() []string {
+	srcs := p.properties.Srcs
+	if p.static() {
+		srcs = append(srcs, p.libraryDecorator.StaticProperties.Static.Srcs...)
+	}
+	if p.shared() {
+		srcs = append(srcs, p.libraryDecorator.SharedProperties.Shared.Srcs...)
+	}
+
+	return srcs
+}
+
 func (p *prebuiltLibraryLinker) shared() bool {
 	return p.libraryDecorator.shared()
 }
@@ -146,13 +166,28 @@
 
 	module.AddProperties(&prebuilt.properties)
 
-	android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
+	srcsSupplier := func() []string {
+		return prebuilt.prebuiltSrcs()
+	}
+
+	android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
 
 	// Prebuilt libraries can be used in SDKs.
 	android.InitSdkAwareModule(module)
 	return module, library
 }
 
+// cc_prebuilt_library installs a precompiled shared library that are
+// listed in the srcs property in the device's directory.
+func PrebuiltLibraryFactory() android.Module {
+	module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+
+	// Prebuilt shared libraries can be included in APEXes
+	android.InitApexModule(module)
+
+	return module.Init()
+}
+
 // cc_prebuilt_library_shared installs a precompiled shared library that are
 // listed in the srcs property in the device's directory.
 func PrebuiltSharedLibraryFactory() android.Module {
@@ -183,6 +218,50 @@
 	return module, library
 }
 
+type prebuiltObjectProperties struct {
+	Srcs []string `android:"path,arch_variant"`
+}
+
+type prebuiltObjectLinker struct {
+	android.Prebuilt
+	objectLinker
+
+	properties prebuiltObjectProperties
+}
+
+func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt {
+	return &p.Prebuilt
+}
+
+var _ prebuiltLinkerInterface = (*prebuiltObjectLinker)(nil)
+
+func (p *prebuiltObjectLinker) link(ctx ModuleContext,
+	flags Flags, deps PathDeps, objs Objects) android.Path {
+	if len(p.properties.Srcs) > 0 {
+		return p.Prebuilt.SingleSourcePath(ctx)
+	}
+	return nil
+}
+
+func newPrebuiltObject() *Module {
+	module := newObject()
+	prebuilt := &prebuiltObjectLinker{
+		objectLinker: objectLinker{
+			baseLinker: NewBaseLinker(nil),
+		},
+	}
+	module.linker = prebuilt
+	module.AddProperties(&prebuilt.properties)
+	android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
+	android.InitSdkAwareModule(module)
+	return module
+}
+
+func prebuiltObjectFactory() android.Module {
+	module := newPrebuiltObject()
+	return module.Init()
+}
+
 type prebuiltBinaryLinker struct {
 	*binaryDecorator
 	prebuiltLinker
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 3d809fc..242d835 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -59,36 +59,49 @@
 			name: "libe",
 			srcs: ["libe.a"],
 		}
+
+		cc_library {
+			name: "libf",
+		}
+
+		cc_prebuilt_library {
+			name: "libf",
+			static: {
+				srcs: ["libf.a"],
+			},
+			shared: {
+				srcs: ["libf.so"],
+			},
+		}
+
+		cc_object {
+			name: "crtx",
+		}
+
+		cc_prebuilt_object {
+			name: "crtx",
+			srcs: ["crtx.o"],
+		}
 	`
 
-	fs := map[string][]byte{
-		"liba.so": nil,
-		"libb.a":  nil,
-		"libd.so": nil,
-		"libe.a":  nil,
-	}
-
-	config := TestConfig(buildDir, android.Android, nil, bp, fs)
-
-	ctx := CreateTestContext()
-
-	ctx.Register(config)
-
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	android.FailIfErrored(t, errs)
-	_, errs = ctx.PrepareBuildActions(config)
-	android.FailIfErrored(t, errs)
+	ctx := testPrebuilt(t, bp)
 
 	// Verify that all the modules exist and that their dependencies were connected correctly
 	liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module()
 	libb := ctx.ModuleForTests("libb", "android_arm64_armv8-a_static").Module()
 	libd := ctx.ModuleForTests("libd", "android_arm64_armv8-a_shared").Module()
 	libe := ctx.ModuleForTests("libe", "android_arm64_armv8-a_static").Module()
+	libfStatic := ctx.ModuleForTests("libf", "android_arm64_armv8-a_static").Module()
+	libfShared := ctx.ModuleForTests("libf", "android_arm64_armv8-a_shared").Module()
+	crtx := ctx.ModuleForTests("crtx", "android_arm64_armv8-a").Module()
 
 	prebuiltLiba := ctx.ModuleForTests("prebuilt_liba", "android_arm64_armv8-a_shared").Module()
 	prebuiltLibb := ctx.ModuleForTests("prebuilt_libb", "android_arm64_armv8-a_static").Module()
 	prebuiltLibd := ctx.ModuleForTests("prebuilt_libd", "android_arm64_armv8-a_shared").Module()
 	prebuiltLibe := ctx.ModuleForTests("prebuilt_libe", "android_arm64_armv8-a_static").Module()
+	prebuiltLibfStatic := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_static").Module()
+	prebuiltLibfShared := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_shared").Module()
+	prebuiltCrtx := ctx.ModuleForTests("prebuilt_crtx", "android_arm64_armv8-a").Module()
 
 	hasDep := func(m android.Module, wantDep android.Module) bool {
 		t.Helper()
@@ -116,4 +129,95 @@
 	if !hasDep(libe, prebuiltLibe) {
 		t.Errorf("libe missing dependency on prebuilt_libe")
 	}
+
+	if !hasDep(libfStatic, prebuiltLibfStatic) {
+		t.Errorf("libf static missing dependency on prebuilt_libf")
+	}
+
+	if !hasDep(libfShared, prebuiltLibfShared) {
+		t.Errorf("libf shared missing dependency on prebuilt_libf")
+	}
+
+	if !hasDep(crtx, prebuiltCrtx) {
+		t.Errorf("crtx missing dependency on prebuilt_crtx")
+	}
+}
+
+func testPrebuilt(t *testing.T, bp string) *android.TestContext {
+
+	fs := map[string][]byte{
+		"liba.so": nil,
+		"libb.a":  nil,
+		"libd.so": nil,
+		"libe.a":  nil,
+		"libf.a":  nil,
+		"libf.so": nil,
+		"crtx.o":  nil,
+	}
+	config := TestConfig(buildDir, android.Android, nil, bp, fs)
+	ctx := CreateTestContext()
+
+	// Enable androidmk support.
+	// * Register the singleton
+	// * Configure that we are inside make
+	// * Add CommonOS to ensure that androidmk processing works.
+	android.RegisterAndroidMkBuildComponents(ctx)
+	android.SetInMakeForTests(config)
+
+	ctx.Register(config)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+	return ctx
+}
+
+func TestPrebuiltLibraryShared(t *testing.T) {
+	ctx := testPrebuilt(t, `
+	cc_prebuilt_library_shared {
+		name: "libtest",
+		srcs: ["libf.so"],
+    strip: {
+        none: true,
+    },
+	}
+	`)
+
+	shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
+	assertString(t, shared.OutputFile().String(), "libf.so")
+}
+
+func TestPrebuiltLibraryStatic(t *testing.T) {
+	ctx := testPrebuilt(t, `
+	cc_prebuilt_library_static {
+		name: "libtest",
+		srcs: ["libf.a"],
+	}
+	`)
+
+	static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
+	assertString(t, static.OutputFile().String(), "libf.a")
+}
+
+func TestPrebuiltLibrary(t *testing.T) {
+	ctx := testPrebuilt(t, `
+	cc_prebuilt_library {
+		name: "libtest",
+		static: {
+			srcs: ["libf.a"],
+		},
+		shared: {
+			srcs: ["libf.so"],
+		},
+    strip: {
+        none: true,
+    },
+	}
+	`)
+
+	shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
+	assertString(t, shared.OutputFile().String(), "libf.so")
+
+	static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
+	assertString(t, static.OutputFile().String(), "libf.a")
 }
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index db61fba..1d94f02 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -173,6 +173,7 @@
 	stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"error.log")))
 	stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"build_error")))
 	stat.AddOutput(status.NewCriticalPath(log))
+	stat.AddOutput(status.NewBuildProgressLog(log, filepath.Join(logsDir, c.logsPrefix+"build_progress.pb")))
 
 	buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
 	buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index ae0dc0b..a3b264e 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -546,7 +546,11 @@
 	var allPhonies android.Paths
 	for _, image := range image.variants {
 		arch := image.target.Arch.ArchType
-		suffix := image.target.String()
+		suffix := arch.String()
+		// Host and target might both use x86 arch. We need to ensure the names are unique.
+		if image.target.Os.Class == android.Host {
+			suffix = "host-" + suffix
+		}
 		// Create a rule to call oatdump.
 		output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt")
 		rule := android.NewRuleBuilder()
@@ -569,7 +573,10 @@
 			Text("echo").FlagWithArg("Output in ", output.String())
 		rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
 
-		allPhonies = append(allPhonies, phony)
+		// TODO: We need to make imageLocations per-variant to make oatdump work on host.
+		if image.target.Os == android.Android {
+			allPhonies = append(allPhonies, phony)
+		}
 	}
 
 	phony := android.PathForPhony(ctx, "dump-oat-boot")
diff --git a/scripts/transitive-deps.sh b/scripts/transitive-deps.sh
index 34e2ecf..23121c6 100755
--- a/scripts/transitive-deps.sh
+++ b/scripts/transitive-deps.sh
@@ -377,7 +377,9 @@
         depth=$(expr ${depth} + 1)
     fi
     ( # recalculate dependencies by combining unique inputs of new deps w. old
+        set +e
         sh -c "${filter}" < "${newDeps}" | cut -d\  -f3- | getDeps
+        set -e
         cat "${oldDeps}"
     ) | sort -u > "${allDeps}"
     # recalculate new dependencies as net additions to old dependencies
@@ -433,7 +435,9 @@
   || [ -n "${notices_out}" ]
 then
     readonly allProj="${tmpFiles}/projects"
+    set +e
     egrep -v '^out[/]' "${allDirs}" | getProjects > "${allProj}"
+    set -e
     if ${showProgress}; then
         echo $(wc -l < "${allProj}")" projects" >&2
     fi
@@ -450,7 +454,9 @@
   '')        : do nothing;;
   *)
     readonly allNotice="${tmpFiles}/notices"
+    set +e
     egrep '^1' "${allDeps}" | cut -d\  -f3- | egrep -v '^out/' > "${allNotice}"
+    set -e
     cat "${allProj}" | while read proj; do
         for f in LICENSE LICENCE NOTICE license.txt notice.txt; do
             if [ -f "${proj}/${f}" ]; then
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 6f9dc3c..27a9518 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -225,6 +225,63 @@
 	`)
 }
 
+func TestSnapshotWithObject(t *testing.T) {
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			native_objects: ["crtobj"],
+		}
+
+		cc_object {
+			name: "crtobj",
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_object {
+    name: "mysdk_crtobj@current",
+    sdk_member_name: "crtobj",
+    stl: "none",
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/crtobj.o"],
+        },
+        arm: {
+            srcs: ["arm/lib/crtobj.o"],
+        },
+    },
+}
+
+cc_prebuilt_object {
+    name: "crtobj",
+    prefer: false,
+    stl: "none",
+    arch: {
+        arm64: {
+            srcs: ["arm64/lib/crtobj.o"],
+        },
+        arm: {
+            srcs: ["arm/lib/crtobj.o"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    native_objects: ["mysdk_crtobj@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/crtobj/android_arm64_armv8-a/crtobj.o -> arm64/lib/crtobj.o
+.intermediates/crtobj/android_arm_armv7-a-neon/crtobj.o -> arm/lib/crtobj.o
+`),
+	)
+}
+
 func TestSnapshotWithCcDuplicateHeaders(t *testing.T) {
 	result := testSdkWithCc(t, `
 		sdk {
@@ -1139,6 +1196,93 @@
 	)
 }
 
+func TestSnapshotWithCcLibrary(t *testing.T) {
+	result := testSdkWithCc(t, `
+		module_exports {
+			name: "myexports",
+			native_libs: ["mynativelib"],
+		}
+
+		cc_library {
+			name: "mynativelib",
+			srcs: [
+				"Test.cpp",
+			],
+			export_include_dirs: ["include"],
+			system_shared_libs: [],
+			stl: "none",
+		}
+	`)
+
+	result.CheckSnapshot("myexports", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library {
+    name: "myexports_mynativelib@current",
+    sdk_member_name: "mynativelib",
+    installable: false,
+    stl: "none",
+    export_include_dirs: ["include/include"],
+    arch: {
+        arm64: {
+            static: {
+                srcs: ["arm64/lib/mynativelib.a"],
+            },
+            shared: {
+                srcs: ["arm64/lib/mynativelib.so"],
+            },
+        },
+        arm: {
+            static: {
+                srcs: ["arm/lib/mynativelib.a"],
+            },
+            shared: {
+                srcs: ["arm/lib/mynativelib.so"],
+            },
+        },
+    },
+}
+
+cc_prebuilt_library {
+    name: "mynativelib",
+    prefer: false,
+    stl: "none",
+    export_include_dirs: ["include/include"],
+    arch: {
+        arm64: {
+            static: {
+                srcs: ["arm64/lib/mynativelib.a"],
+            },
+            shared: {
+                srcs: ["arm64/lib/mynativelib.so"],
+            },
+        },
+        arm: {
+            static: {
+                srcs: ["arm/lib/mynativelib.a"],
+            },
+            shared: {
+                srcs: ["arm/lib/mynativelib.so"],
+            },
+        },
+    },
+}
+
+module_exports_snapshot {
+    name: "myexports@current",
+    native_libs: ["myexports_mynativelib@current"],
+}
+`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+.intermediates/mynativelib/android_arm64_armv8-a_static/mynativelib.a -> arm64/lib/mynativelib.a
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm_armv7-a-neon_static/mynativelib.a -> arm/lib/mynativelib.a
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so`),
+	)
+}
+
 func TestHostSnapshotWithMultiLib64(t *testing.T) {
 	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
 	SkipIfNotLinux(t)
diff --git a/sdk/update.go b/sdk/update.go
index 779ba1a..ce25fc4 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -21,6 +21,7 @@
 	"strings"
 
 	"android/soong/apex"
+	"android/soong/cc"
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -793,17 +794,278 @@
 type osTypeSpecificInfo struct {
 	baseInfo
 
-	// The list of arch type specific info for this os type.
-	archTypes []*archTypeSpecificInfo
+	osType android.OsType
 
-	// True if the member has common arch variants for this os type.
-	commonArch bool
+	// The list of arch type specific info for this os type.
+	//
+	// Nil if there is one variant whose arch type is common
+	archInfos []*archTypeSpecificInfo
+}
+
+type variantPropertiesFactoryFunc func() android.SdkMemberProperties
+
+// Create a new osTypeSpecificInfo for the specified os type and its properties
+// structures populated with information from the variants.
+func newOsTypeSpecificInfo(osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.SdkAware) *osTypeSpecificInfo {
+	osInfo := &osTypeSpecificInfo{
+		osType: osType,
+	}
+
+	osSpecificVariantPropertiesFactory := func() android.SdkMemberProperties {
+		properties := variantPropertiesFactory()
+		properties.Base().Os = osType
+		return properties
+	}
+
+	// Create a structure into which properties common across the architectures in
+	// this os type will be stored.
+	osInfo.Properties = osSpecificVariantPropertiesFactory()
+
+	// Group the variants by arch type.
+	var variantsByArchName = make(map[string][]android.SdkAware)
+	var archTypes []android.ArchType
+	for _, variant := range osTypeVariants {
+		archType := variant.Target().Arch.ArchType
+		archTypeName := archType.Name
+		if _, ok := variantsByArchName[archTypeName]; !ok {
+			archTypes = append(archTypes, archType)
+		}
+
+		variantsByArchName[archTypeName] = append(variantsByArchName[archTypeName], variant)
+	}
+
+	if commonVariants, ok := variantsByArchName["common"]; ok {
+		if len(osTypeVariants) != 1 {
+			panic("Expected to only have 1 variant when arch type is common but found " + string(len(osTypeVariants)))
+		}
+
+		// A common arch type only has one variant and its properties should be treated
+		// as common to the os type.
+		osInfo.Properties.PopulateFromVariant(commonVariants[0])
+	} else {
+		// Create an arch specific info for each supported architecture type.
+		for _, archType := range archTypes {
+			archTypeName := archType.Name
+
+			archVariants := variantsByArchName[archTypeName]
+			archInfo := newArchSpecificInfo(archType, osSpecificVariantPropertiesFactory, archVariants)
+
+			osInfo.archInfos = append(osInfo.archInfos, archInfo)
+		}
+	}
+
+	return osInfo
+}
+
+// Optimize the properties by extracting common properties from arch type specific
+// properties into os type specific properties.
+func (osInfo *osTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+	// Nothing to do if there is only a single common architecture.
+	if len(osInfo.archInfos) == 0 {
+		return
+	}
+
+	var archPropertiesList []android.SdkMemberProperties
+	for _, archInfo := range osInfo.archInfos {
+		// Optimize the arch properties first.
+		archInfo.optimizeProperties(commonValueExtractor)
+
+		archPropertiesList = append(archPropertiesList, archInfo.Properties)
+	}
+
+	commonValueExtractor.extractCommonProperties(osInfo.Properties, archPropertiesList)
+
+	// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
+	var multilib string
+	archVariantCount := len(osInfo.archInfos)
+	if archVariantCount == 2 {
+		multilib = "both"
+	} else if archVariantCount == 1 {
+		if strings.HasSuffix(osInfo.archInfos[0].archType.Name, "64") {
+			multilib = "64"
+		} else {
+			multilib = "32"
+		}
+	}
+
+	osInfo.Properties.Base().Compile_multilib = multilib
+}
+
+// Add the properties for an os to a property set.
+//
+// Maps the properties related to the os variants through to an appropriate
+// module structure that will produce equivalent set of variants when it is
+// processed in a build.
+func (osInfo *osTypeSpecificInfo) addToPropertySet(
+	builder *snapshotBuilder,
+	bpModule android.BpModule,
+	targetPropertySet android.BpPropertySet) {
+
+	var osPropertySet android.BpPropertySet
+	var archPropertySet android.BpPropertySet
+	var archOsPrefix string
+	if osInfo.Properties.Base().Os_count == 1 {
+		// There is only one os type present in the variants so don't bother
+		// with adding target specific properties.
+
+		// Create a structure that looks like:
+		// module_type {
+		//   name: "...",
+		//   ...
+		//   <common properties>
+		//   ...
+		//   <single os type specific properties>
+		//
+		//   arch: {
+		//     <arch specific sections>
+		//   }
+		//
+		osPropertySet = bpModule
+		archPropertySet = osPropertySet.AddPropertySet("arch")
+
+		// Arch specific properties need to be added to an arch specific section
+		// within arch.
+		archOsPrefix = ""
+	} else {
+		// Create a structure that looks like:
+		// module_type {
+		//   name: "...",
+		//   ...
+		//   <common properties>
+		//   ...
+		//   target: {
+		//     <arch independent os specific sections, e.g. android>
+		//     ...
+		//     <arch and os specific sections, e.g. android_x86>
+		//   }
+		//
+		osType := osInfo.osType
+		osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
+		archPropertySet = targetPropertySet
+
+		// Arch specific properties need to be added to an os and arch specific
+		// section prefixed with <os>_.
+		archOsPrefix = osType.Name + "_"
+	}
+
+	// Add the os specific but arch independent properties to the module.
+	osInfo.Properties.AddToPropertySet(builder.ctx, builder, osPropertySet)
+
+	// Add arch (and possibly os) specific sections for each set of arch (and possibly
+	// os) specific properties.
+	//
+	// The archInfos list will be empty if the os contains variants for the common
+	// architecture.
+	for _, archInfo := range osInfo.archInfos {
+		archInfo.addToPropertySet(builder, archPropertySet, archOsPrefix)
+	}
 }
 
 type archTypeSpecificInfo struct {
 	baseInfo
 
 	archType android.ArchType
+
+	linkInfos []*linkTypeSpecificInfo
+}
+
+// Create a new archTypeSpecificInfo for the specified arch type and its properties
+// structures populated with information from the variants.
+func newArchSpecificInfo(archType android.ArchType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.SdkAware) *archTypeSpecificInfo {
+
+	// Create an arch specific info into which the variant properties can be copied.
+	archInfo := &archTypeSpecificInfo{archType: archType}
+
+	// Create the properties into which the arch type specific properties will be
+	// added.
+	archInfo.Properties = variantPropertiesFactory()
+
+	if len(archVariants) == 1 {
+		archInfo.Properties.PopulateFromVariant(archVariants[0])
+	} else {
+		// There is more than one variant for this arch type which must be differentiated
+		// by link type.
+		for _, linkVariant := range archVariants {
+			linkType := getLinkType(linkVariant)
+			if linkType == "" {
+				panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(archVariants)))
+			} else {
+				linkInfo := newLinkSpecificInfo(linkType, variantPropertiesFactory, linkVariant)
+
+				archInfo.linkInfos = append(archInfo.linkInfos, linkInfo)
+			}
+		}
+	}
+
+	return archInfo
+}
+
+// Get the link type of the variant
+//
+// If the variant is not differentiated by link type then it returns "",
+// otherwise it returns one of "static" or "shared".
+func getLinkType(variant android.Module) string {
+	linkType := ""
+	if linkable, ok := variant.(cc.LinkableInterface); ok {
+		if linkable.Shared() && linkable.Static() {
+			panic(fmt.Errorf("expected variant %q to be either static or shared but was both", variant.String()))
+		} else if linkable.Shared() {
+			linkType = "shared"
+		} else if linkable.Static() {
+			linkType = "static"
+		} else {
+			panic(fmt.Errorf("expected variant %q to be either static or shared but was neither", variant.String()))
+		}
+	}
+	return linkType
+}
+
+// Optimize the properties by extracting common properties from link type specific
+// properties into arch type specific properties.
+func (archInfo *archTypeSpecificInfo) optimizeProperties(commonValueExtractor *commonValueExtractor) {
+	if len(archInfo.linkInfos) == 0 {
+		return
+	}
+
+	var propertiesList []android.SdkMemberProperties
+	for _, linkInfo := range archInfo.linkInfos {
+		propertiesList = append(propertiesList, linkInfo.Properties)
+	}
+
+	commonValueExtractor.extractCommonProperties(archInfo.Properties, propertiesList)
+}
+
+// Add the properties for an arch type to a property set.
+func (archInfo *archTypeSpecificInfo) addToPropertySet(builder *snapshotBuilder, archPropertySet android.BpPropertySet, archOsPrefix string) {
+	archTypeName := archInfo.archType.Name
+	archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
+	archInfo.Properties.AddToPropertySet(builder.ctx, builder, archTypePropertySet)
+
+	for _, linkInfo := range archInfo.linkInfos {
+		linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
+		linkInfo.Properties.AddToPropertySet(builder.ctx, builder, linkPropertySet)
+	}
+}
+
+type linkTypeSpecificInfo struct {
+	baseInfo
+
+	linkType string
+}
+
+// Create a new linkTypeSpecificInfo for the specified link type and its properties
+// structures populated with information from the variant.
+func newLinkSpecificInfo(linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.SdkAware) *linkTypeSpecificInfo {
+	linkInfo := &linkTypeSpecificInfo{
+		baseInfo: baseInfo{
+			// Create the properties into which the link type specific properties will be
+			// added.
+			Properties: variantPropertiesFactory(),
+		},
+		linkType: linkType,
+	}
+	linkInfo.Properties.PopulateFromVariant(linkVariant)
+	return linkInfo
 }
 
 func (s *sdk) createMemberSnapshot(sdkModuleContext android.ModuleContext, builder *snapshotBuilder, member *sdkMember, bpModule android.BpModule) {
@@ -819,18 +1081,18 @@
 	}
 
 	osCount := len(variantsByOsType)
-	createVariantPropertiesStruct := func(os android.OsType) android.SdkMemberProperties {
+	variantPropertiesFactory := func() android.SdkMemberProperties {
 		properties := memberType.CreateVariantPropertiesStruct()
 		base := properties.Base()
 		base.Os_count = osCount
-		base.Os = os
 		return properties
 	}
 
 	osTypeToInfo := make(map[android.OsType]*osTypeSpecificInfo)
 
 	// The set of properties that are common across all architectures and os types.
-	commonProperties := createVariantPropertiesStruct(android.CommonOS)
+	commonProperties := variantPropertiesFactory()
+	commonProperties.Base().Os = android.CommonOS
 
 	// Create common value extractor that can be used to optimize the properties.
 	commonValueExtractor := newCommonValueExtractor(commonProperties)
@@ -840,67 +1102,14 @@
 	var osSpecificPropertiesList []android.SdkMemberProperties
 
 	for osType, osTypeVariants := range variantsByOsType {
-		// Group the properties for each variant by arch type within the os.
-		osInfo := &osTypeSpecificInfo{}
+		osInfo := newOsTypeSpecificInfo(osType, variantPropertiesFactory, osTypeVariants)
 		osTypeToInfo[osType] = osInfo
-
-		// Create a structure into which properties common across the architectures in
-		// this os type will be stored. Add it to the list of os type specific yet
-		// architecture independent properties structs.
-		osInfo.Properties = createVariantPropertiesStruct(osType)
+		// Add the os specific properties to a list of os type specific yet architecture
+		// independent properties structs.
 		osSpecificPropertiesList = append(osSpecificPropertiesList, osInfo.Properties)
 
-		commonArch := false
-		for _, variant := range osTypeVariants {
-			var properties android.SdkMemberProperties
-
-			// Get the info associated with the arch type inside the os info.
-			archType := variant.Target().Arch.ArchType
-
-			if archType.Name == "common" {
-				// The arch type is common so populate the common properties directly.
-				properties = osInfo.Properties
-
-				commonArch = true
-			} else {
-				archInfo := &archTypeSpecificInfo{archType: archType}
-				properties = createVariantPropertiesStruct(osType)
-				archInfo.Properties = properties
-
-				osInfo.archTypes = append(osInfo.archTypes, archInfo)
-			}
-
-			properties.PopulateFromVariant(variant)
-		}
-
-		if commonArch {
-			if len(osTypeVariants) != 1 {
-				panic("Expected to only have 1 variant when arch type is common but found " + string(len(variants)))
-			}
-		} else {
-			var archPropertiesList []android.SdkMemberProperties
-			for _, archInfo := range osInfo.archTypes {
-				archPropertiesList = append(archPropertiesList, archInfo.Properties)
-			}
-
-			commonValueExtractor.extractCommonProperties(osInfo.Properties, archPropertiesList)
-
-			// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
-			var multilib string
-			archVariantCount := len(osInfo.archTypes)
-			if archVariantCount == 2 {
-				multilib = "both"
-			} else if archVariantCount == 1 {
-				if strings.HasSuffix(osInfo.archTypes[0].archType.Name, "64") {
-					multilib = "64"
-				} else {
-					multilib = "32"
-				}
-			}
-
-			osInfo.commonArch = commonArch
-			osInfo.Properties.Base().Compile_multilib = multilib
-		}
+		// Optimize the properties across all the variants for a specific os type.
+		osInfo.optimizeProperties(commonValueExtractor)
 	}
 
 	// Extract properties which are common across all architectures and os types.
@@ -920,68 +1129,7 @@
 			continue
 		}
 
-		var osPropertySet android.BpPropertySet
-		var archOsPrefix string
-		if len(osTypeToInfo) == 1 {
-			// There is only one os type present in the variants sp don't bother
-			// with adding target specific properties.
-
-			// Create a structure that looks like:
-			// module_type {
-			//   name: "...",
-			//   ...
-			//   <common properties>
-			//   ...
-			//   <single os type specific properties>
-			//
-			//   arch: {
-			//     <arch specific sections>
-			//   }
-			//
-			osPropertySet = bpModule
-
-			// Arch specific properties need to be added to an arch specific section
-			// within arch.
-			archOsPrefix = ""
-		} else {
-			// Create a structure that looks like:
-			// module_type {
-			//   name: "...",
-			//   ...
-			//   <common properties>
-			//   ...
-			//   target: {
-			//     <arch independent os specific sections, e.g. android>
-			//     ...
-			//     <arch and os specific sections, e.g. android_x86>
-			//   }
-			//
-			osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
-
-			// Arch specific properties need to be added to an os and arch specific
-			// section prefixed with <os>_.
-			archOsPrefix = osType.Name + "_"
-		}
-
-		osInfo.Properties.AddToPropertySet(sdkModuleContext, builder, osPropertySet)
-		if !osInfo.commonArch {
-			// Either add the arch specific sections into the target or arch sections
-			// depending on whether they will also be os specific.
-			var archPropertySet android.BpPropertySet
-			if archOsPrefix == "" {
-				archPropertySet = osPropertySet.AddPropertySet("arch")
-			} else {
-				archPropertySet = targetPropertySet
-			}
-
-			// Add arch (and possibly os) specific sections for each set of
-			// arch (and possibly os) specific properties.
-			for _, av := range osInfo.archTypes {
-				archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + av.archType.Name)
-
-				av.Properties.AddToPropertySet(sdkModuleContext, builder, archTypePropertySet)
-			}
-		}
+		osInfo.addToPropertySet(builder, bpModule, targetPropertySet)
 	}
 }
 
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 36d4f04..95d049a 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -111,6 +111,9 @@
 		productOut("obj/PACKAGING"),
 		productOut("ramdisk"),
 		productOut("debug_ramdisk"),
+		productOut("vendor-ramdisk"),
+		productOut("vendor-ramdisk-debug.cpio.gz"),
+		productOut("vendor_debug_ramdisk"),
 		productOut("test_harness_ramdisk"),
 		productOut("recovery"),
 		productOut("root"),
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 4fc1f01..dfc3be1 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -128,6 +128,16 @@
 			"GOMA_USE_LOCAL",
 
 			// RBE client
+			"RBE_compare",
+			"RBE_exec_root",
+			"RBE_exec_strategy",
+			"RBE_invocation_id",
+			"RBE_log_dir",
+			"RBE_platform",
+			"RBE_remote_accept_cache",
+			"RBE_remote_update_cache",
+			"RBE_server_address",
+			// TODO: remove old FLAG_ variables.
 			"FLAG_compare",
 			"FLAG_exec_root",
 			"FLAG_exec_strategy",
diff --git a/ui/status/Android.bp b/ui/status/Android.bp
index ec929b3..19e5a2a 100644
--- a/ui/status/Android.bp
+++ b/ui/status/Android.bp
@@ -20,6 +20,7 @@
         "soong-ui-logger",
         "soong-ui-status-ninja_frontend",
         "soong-ui-status-build_error_proto",
+        "soong-ui-status-build_progress_proto",
     ],
     srcs: [
         "critical_path.go",
@@ -53,3 +54,12 @@
         "build_error_proto/build_error.pb.go",
     ],
 }
+
+bootstrap_go_package {
+    name: "soong-ui-status-build_progress_proto",
+    pkgPath: "android/soong/ui/status/build_progress_proto",
+    deps: ["golang-protobuf-proto"],
+    srcs: [
+        "build_progress_proto/build_progress.pb.go",
+    ],
+}
diff --git a/ui/status/build_progress_proto/build_progress.pb.go b/ui/status/build_progress_proto/build_progress.pb.go
new file mode 100644
index 0000000..f63c157
--- /dev/null
+++ b/ui/status/build_progress_proto/build_progress.pb.go
@@ -0,0 +1,115 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: build_progress.proto
+
+package soong_build_progress_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 BuildProgress struct {
+	// Total number of actions in a build. The total actions will increase
+	// and might decrease during the course of a build.
+	TotalActions *uint64 `protobuf:"varint,1,opt,name=total_actions,json=totalActions" json:"total_actions,omitempty"`
+	// Total number of completed build actions. This value will never decrease
+	// and finished_actions <= total_actions. At one point of the build, the
+	// finished_actions will be equal to total_actions. This may not represent
+	// that the build is completed as the total_actions may be increased for
+	// additional counted work or is doing non-counted work.
+	FinishedActions *uint64 `protobuf:"varint,2,opt,name=finished_actions,json=finishedActions" json:"finished_actions,omitempty"`
+	// Total number of current actions being executed during a course of a
+	// build and current_actions + finished_actions <= total_actions.
+	CurrentActions *uint64 `protobuf:"varint,3,opt,name=current_actions,json=currentActions" json:"current_actions,omitempty"`
+	// Total number of actions that reported as a failure.
+	FailedActions        *uint64  `protobuf:"varint,4,opt,name=failed_actions,json=failedActions" json:"failed_actions,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *BuildProgress) Reset()         { *m = BuildProgress{} }
+func (m *BuildProgress) String() string { return proto.CompactTextString(m) }
+func (*BuildProgress) ProtoMessage()    {}
+func (*BuildProgress) Descriptor() ([]byte, []int) {
+	return fileDescriptor_a8a463f8e30dab2e, []int{0}
+}
+
+func (m *BuildProgress) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_BuildProgress.Unmarshal(m, b)
+}
+func (m *BuildProgress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_BuildProgress.Marshal(b, m, deterministic)
+}
+func (m *BuildProgress) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_BuildProgress.Merge(m, src)
+}
+func (m *BuildProgress) XXX_Size() int {
+	return xxx_messageInfo_BuildProgress.Size(m)
+}
+func (m *BuildProgress) XXX_DiscardUnknown() {
+	xxx_messageInfo_BuildProgress.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BuildProgress proto.InternalMessageInfo
+
+func (m *BuildProgress) GetTotalActions() uint64 {
+	if m != nil && m.TotalActions != nil {
+		return *m.TotalActions
+	}
+	return 0
+}
+
+func (m *BuildProgress) GetFinishedActions() uint64 {
+	if m != nil && m.FinishedActions != nil {
+		return *m.FinishedActions
+	}
+	return 0
+}
+
+func (m *BuildProgress) GetCurrentActions() uint64 {
+	if m != nil && m.CurrentActions != nil {
+		return *m.CurrentActions
+	}
+	return 0
+}
+
+func (m *BuildProgress) GetFailedActions() uint64 {
+	if m != nil && m.FailedActions != nil {
+		return *m.FailedActions
+	}
+	return 0
+}
+
+func init() {
+	proto.RegisterType((*BuildProgress)(nil), "soong_build_progress.BuildProgress")
+}
+
+func init() { proto.RegisterFile("build_progress.proto", fileDescriptor_a8a463f8e30dab2e) }
+
+var fileDescriptor_a8a463f8e30dab2e = []byte{
+	// 165 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x49, 0x2a, 0xcd, 0xcc,
+	0x49, 0x89, 0x2f, 0x28, 0xca, 0x4f, 0x2f, 0x4a, 0x2d, 0x2e, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9,
+	0x17, 0x12, 0x29, 0xce, 0xcf, 0xcf, 0x4b, 0x8f, 0x47, 0x95, 0x53, 0x5a, 0xcf, 0xc8, 0xc5, 0xeb,
+	0x04, 0x12, 0x0a, 0x80, 0x8a, 0x08, 0x29, 0x73, 0xf1, 0x96, 0xe4, 0x97, 0x24, 0xe6, 0xc4, 0x27,
+	0x26, 0x97, 0x64, 0xe6, 0xe7, 0x15, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x04, 0xf1, 0x80, 0x05,
+	0x1d, 0x21, 0x62, 0x42, 0x9a, 0x5c, 0x02, 0x69, 0x99, 0x79, 0x99, 0xc5, 0x19, 0xa9, 0x29, 0x70,
+	0x75, 0x4c, 0x60, 0x75, 0xfc, 0x30, 0x71, 0x98, 0x52, 0x75, 0x2e, 0xfe, 0xe4, 0xd2, 0xa2, 0xa2,
+	0xd4, 0xbc, 0x12, 0xb8, 0x4a, 0x66, 0xb0, 0x4a, 0x3e, 0xa8, 0x30, 0x4c, 0xa1, 0x2a, 0x17, 0x5f,
+	0x5a, 0x62, 0x66, 0x0e, 0x92, 0x89, 0x2c, 0x60, 0x75, 0xbc, 0x10, 0x51, 0xa8, 0x32, 0x27, 0x99,
+	0x28, 0x29, 0x6c, 0x3e, 0x89, 0x07, 0xfb, 0x12, 0x10, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x6e, 0xc1,
+	0xef, 0xfc, 0x00, 0x00, 0x00,
+}
diff --git a/ui/status/completion_proto/build_completion.proto b/ui/status/build_progress_proto/build_progress.proto
similarity index 86%
rename from ui/status/completion_proto/build_completion.proto
rename to ui/status/build_progress_proto/build_progress.proto
index 939545e..d78060a 100644
--- a/ui/status/completion_proto/build_completion.proto
+++ b/ui/status/build_progress_proto/build_progress.proto
@@ -14,10 +14,10 @@
 
 syntax = "proto2";
 
-package soong_build_completion_status;
-option go_package = "soong_build_completion_status_proto";
+package soong_build_progress;
+option go_package = "soong_build_progress_proto";
 
-message BuildCompletionStatus {
+message BuildProgress {
   // Total number of actions in a build. The total actions will increase
   // and might decrease during the course of a build.
   optional uint64 total_actions = 1;
@@ -32,4 +32,7 @@
   // Total number of current actions being executed during a course of a
   // build and current_actions + finished_actions <= total_actions.
   optional uint64 current_actions = 3;
+
+  // Total number of actions that reported as a failure.
+  optional uint64 failed_actions = 4;
 }
diff --git a/ui/status/completion_proto/regen.sh b/ui/status/build_progress_proto/regen.sh
similarity index 82%
rename from ui/status/completion_proto/regen.sh
rename to ui/status/build_progress_proto/regen.sh
index 652df08..572785d 100755
--- a/ui/status/completion_proto/regen.sh
+++ b/ui/status/build_progress_proto/regen.sh
@@ -12,6 +12,6 @@
   die "could not find aprotoc. ${error_msg}"
 fi
 
-if ! aprotoc --go_out=paths=source_relative:. build_completion.proto; then
+if ! aprotoc --go_out=paths=source_relative:. build_progress.proto; then
   die "build failed. ${error_msg}"
 fi
diff --git a/ui/status/completion_proto/build_completion.pb.go b/ui/status/completion_proto/build_completion.pb.go
deleted file mode 100644
index 526e19a..0000000
--- a/ui/status/completion_proto/build_completion.pb.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Code generated by protoc-gen-go. DO NOT EDIT.
-// source: build_completion.proto
-
-package soong_build_completion_status_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 BuildCompletionStatus struct {
-	// Total number of actions in a build. The total actions will increase
-	// and might decrease during the course of a build.
-	TotalActions *uint64 `protobuf:"varint,1,opt,name=total_actions,json=totalActions" json:"total_actions,omitempty"`
-	// Total number of completed build actions. This value will never decrease
-	// and finished_actions <= total_actions. At one point of the build, the
-	// finished_actions will be equal to total_actions. This may not represent
-	// that the build is completed as the total_actions may be increased for
-	// additional counted work or is doing non-counted work.
-	FinishedActions *uint64 `protobuf:"varint,2,opt,name=finished_actions,json=finishedActions" json:"finished_actions,omitempty"`
-	// Total number of current actions being executed during a course of a
-	// build and current_actions + finished_actions <= total_actions.
-	CurrentActions       *uint64  `protobuf:"varint,3,opt,name=current_actions,json=currentActions" json:"current_actions,omitempty"`
-	XXX_NoUnkeyedLiteral struct{} `json:"-"`
-	XXX_unrecognized     []byte   `json:"-"`
-	XXX_sizecache        int32    `json:"-"`
-}
-
-func (m *BuildCompletionStatus) Reset()         { *m = BuildCompletionStatus{} }
-func (m *BuildCompletionStatus) String() string { return proto.CompactTextString(m) }
-func (*BuildCompletionStatus) ProtoMessage()    {}
-func (*BuildCompletionStatus) Descriptor() ([]byte, []int) {
-	return fileDescriptor_7f03c01d09a4e764, []int{0}
-}
-
-func (m *BuildCompletionStatus) XXX_Unmarshal(b []byte) error {
-	return xxx_messageInfo_BuildCompletionStatus.Unmarshal(m, b)
-}
-func (m *BuildCompletionStatus) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
-	return xxx_messageInfo_BuildCompletionStatus.Marshal(b, m, deterministic)
-}
-func (m *BuildCompletionStatus) XXX_Merge(src proto.Message) {
-	xxx_messageInfo_BuildCompletionStatus.Merge(m, src)
-}
-func (m *BuildCompletionStatus) XXX_Size() int {
-	return xxx_messageInfo_BuildCompletionStatus.Size(m)
-}
-func (m *BuildCompletionStatus) XXX_DiscardUnknown() {
-	xxx_messageInfo_BuildCompletionStatus.DiscardUnknown(m)
-}
-
-var xxx_messageInfo_BuildCompletionStatus proto.InternalMessageInfo
-
-func (m *BuildCompletionStatus) GetTotalActions() uint64 {
-	if m != nil && m.TotalActions != nil {
-		return *m.TotalActions
-	}
-	return 0
-}
-
-func (m *BuildCompletionStatus) GetFinishedActions() uint64 {
-	if m != nil && m.FinishedActions != nil {
-		return *m.FinishedActions
-	}
-	return 0
-}
-
-func (m *BuildCompletionStatus) GetCurrentActions() uint64 {
-	if m != nil && m.CurrentActions != nil {
-		return *m.CurrentActions
-	}
-	return 0
-}
-
-func init() {
-	proto.RegisterType((*BuildCompletionStatus)(nil), "soong_build_completion_status.BuildCompletionStatus")
-}
-
-func init() { proto.RegisterFile("build_completion.proto", fileDescriptor_7f03c01d09a4e764) }
-
-var fileDescriptor_7f03c01d09a4e764 = []byte{
-	// 158 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x4b, 0x2a, 0xcd, 0xcc,
-	0x49, 0x89, 0x4f, 0xce, 0xcf, 0x2d, 0xc8, 0x49, 0x2d, 0xc9, 0xcc, 0xcf, 0xd3, 0x2b, 0x28, 0xca,
-	0x2f, 0xc9, 0x17, 0x92, 0x2d, 0xce, 0xcf, 0xcf, 0x4b, 0x8f, 0x47, 0x97, 0x8d, 0x2f, 0x2e, 0x49,
-	0x2c, 0x29, 0x2d, 0x56, 0x9a, 0xc0, 0xc8, 0x25, 0xea, 0x04, 0x92, 0x73, 0x86, 0x4b, 0x05, 0x83,
-	0x65, 0x84, 0x94, 0xb9, 0x78, 0x4b, 0xf2, 0x4b, 0x12, 0x73, 0xe2, 0x13, 0x93, 0x41, 0xa2, 0xc5,
-	0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x2c, 0x41, 0x3c, 0x60, 0x41, 0x47, 0x88, 0x98, 0x90, 0x26, 0x97,
-	0x40, 0x5a, 0x66, 0x5e, 0x66, 0x71, 0x46, 0x6a, 0x0a, 0x5c, 0x1d, 0x13, 0x58, 0x1d, 0x3f, 0x4c,
-	0x1c, 0xa6, 0x54, 0x9d, 0x8b, 0x3f, 0xb9, 0xb4, 0xa8, 0x28, 0x35, 0xaf, 0x04, 0xae, 0x92, 0x19,
-	0xac, 0x92, 0x0f, 0x2a, 0x0c, 0x55, 0xe8, 0xa4, 0x1a, 0xa5, 0x8c, 0xd7, 0xcd, 0xf1, 0x60, 0x8f,
-	0x01, 0x02, 0x00, 0x00, 0xff, 0xff, 0x13, 0x08, 0x7b, 0x38, 0xf1, 0x00, 0x00, 0x00,
-}
diff --git a/ui/status/log.go b/ui/status/log.go
index d407248..4a08acb 100644
--- a/ui/status/log.go
+++ b/ui/status/log.go
@@ -20,12 +20,14 @@
 	"fmt"
 	"io"
 	"io/ioutil"
+	"os"
 	"strings"
 
 	"github.com/golang/protobuf/proto"
 
 	"android/soong/ui/logger"
 	"android/soong/ui/status/build_error_proto"
+	"android/soong/ui/status/build_progress_proto"
 )
 
 type verboseLog struct {
@@ -154,6 +156,7 @@
 }
 
 func NewProtoErrorLog(log logger.Logger, filename string) StatusOutput {
+	os.Remove(filename)
 	return &errorProtoLog{
 		errorProto: soong_build_error_proto.BuildError{},
 		filename:   filename,
@@ -175,20 +178,17 @@
 		Artifacts:   result.Outputs,
 		Error:       proto.String(result.Error.Error()),
 	})
-}
 
-func (e *errorProtoLog) Flush() {
-	data, err := proto.Marshal(&e.errorProto)
-	if err != nil {
-		e.log.Printf("Failed to marshal build status proto: %v\n", err)
-		return
-	}
-	err = ioutil.WriteFile(e.filename, []byte(data), 0644)
+	err := writeToFile(&e.errorProto, e.filename)
 	if err != nil {
 		e.log.Printf("Failed to write file %s: %v\n", e.filename, err)
 	}
 }
 
+func (e *errorProtoLog) Flush() {
+	//Not required.
+}
+
 func (e *errorProtoLog) Message(level MsgLevel, message string) {
 	if level > ErrorLvl {
 		e.errorProto.ErrorMessages = append(e.errorProto.ErrorMessages, message)
@@ -198,3 +198,75 @@
 func (e *errorProtoLog) Write(p []byte) (int, error) {
 	return 0, errors.New("not supported")
 }
+
+type buildProgressLog struct {
+	filename      string
+	log           logger.Logger
+	failedActions uint64
+}
+
+func NewBuildProgressLog(log logger.Logger, filename string) StatusOutput {
+	return &buildProgressLog{
+		filename:      filename,
+		log:           log,
+		failedActions: 0,
+	}
+}
+
+func (b *buildProgressLog) StartAction(action *Action, counts Counts) {
+	b.updateCounters(counts)
+}
+
+func (b *buildProgressLog) FinishAction(result ActionResult, counts Counts) {
+	if result.Error != nil {
+		b.failedActions++
+	}
+	b.updateCounters(counts)
+}
+
+func (b *buildProgressLog) Flush() {
+	//Not required.
+}
+
+func (b *buildProgressLog) Message(level MsgLevel, message string) {
+	// Not required.
+}
+
+func (b *buildProgressLog) Write(p []byte) (int, error) {
+	return 0, errors.New("not supported")
+}
+
+func (b *buildProgressLog) updateCounters(counts Counts) {
+	err := writeToFile(
+		&soong_build_progress_proto.BuildProgress{
+			CurrentActions:  proto.Uint64(uint64(counts.RunningActions)),
+			FinishedActions: proto.Uint64(uint64(counts.FinishedActions)),
+			TotalActions:    proto.Uint64(uint64(counts.TotalActions)),
+			FailedActions:   proto.Uint64(b.failedActions),
+		},
+		b.filename,
+	)
+	if err != nil {
+		b.log.Printf("Failed to write file %s: %v\n", b.filename, err)
+	}
+}
+
+func writeToFile(pb proto.Message, outputPath string) (err error) {
+	data, err := proto.Marshal(pb)
+	if err != nil {
+		return err
+	}
+
+	tempPath := outputPath + ".tmp"
+	err = ioutil.WriteFile(tempPath, []byte(data), 0644)
+	if err != nil {
+		return err
+	}
+
+	err = os.Rename(tempPath, outputPath)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}