Merge "Simplify the construction of class loader contexts for system server jars."
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/sdk.go b/android/sdk.go
index 5c7b329..66094cd 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -145,10 +145,6 @@
 	return s.properties.RequiredSdks
 }
 
-func (s *SdkBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder) {
-	sdkModuleContext.ModuleErrorf("module type " + sdkModuleContext.OtherModuleType(s.module) + " cannot be used in an sdk")
-}
-
 // InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
 // SdkBase.
 func InitSdkAwareModule(m SdkAware) {
@@ -304,10 +300,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)
@@ -319,17 +316,6 @@
 	// the module is not allowed in whichever sdk property it was added.
 	IsInstance(module Module) bool
 
-	// Build the snapshot for the SDK member
-	//
-	// The ModuleContext provided is for the SDK module, so information for
-	// variants in the supplied member can be accessed using the Other... methods.
-	//
-	// The SdkMember is guaranteed to contain variants for which the
-	// IsInstance(Module) method returned true.
-	//
-	// deprecated Use AddPrebuiltModule() instead.
-	BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember)
-
 	// Add a prebuilt module that the sdk will populate.
 	//
 	// Returning nil from this will cause the sdk module type to use the deprecated BuildSnapshot
@@ -356,7 +342,7 @@
 	//   structure and calls AddToPropertySet(...) on the properties struct to add the member
 	//   specific properties in the correct place in the structure.
 	//
-	AddPrebuiltModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) BpModule
+	AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule
 
 	// Create a structure into which variant specific properties can be added.
 	CreateVariantPropertiesStruct() SdkMemberProperties
@@ -381,19 +367,6 @@
 	return b.TransitiveSdkMembers
 }
 
-func (b *SdkMemberTypeBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) {
-	panic("override AddPrebuiltModule")
-}
-
-func (b *SdkMemberTypeBase) AddPrebuiltModule(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember) BpModule {
-	// Returning nil causes the legacy BuildSnapshot method to be used.
-	return nil
-}
-
-func (b *SdkMemberTypeBase) CreateVariantPropertiesStruct() SdkMemberProperties {
-	panic("override me")
-}
-
 // Encapsulates the information about registered SdkMemberTypes.
 type SdkMemberTypesRegistry struct {
 	// The list of types sorted by property name.
@@ -465,14 +438,29 @@
 // Contains common properties that apply across many different member types. These
 // are not affected by the optimization to extract common values.
 type SdkMemberPropertiesBase struct {
-	// The setting to use for the compile_multilib property.
-	Compile_multilib string `sdk:"keep"`
-
 	// The number of unique os types supported by the member variants.
+	//
+	// If a member has a variant with more than one os type then it will need to differentiate
+	// the locations of any of their prebuilt files in the snapshot by os type to prevent them
+	// from colliding. See OsPrefix().
+	//
+	// This property is the same for all variants of a member and so would be optimized away
+	// if it was not explicitly kept.
 	Os_count int `sdk:"keep"`
 
 	// The os type for which these properties refer.
+	//
+	// Provided to allow a member to differentiate between os types in the locations of their
+	// prebuilt files when it supports more than one os type.
+	//
+	// This property is the same for all os type specific variants of a member and so would be
+	// optimized away if it was not explicitly kept.
 	Os OsType `sdk:"keep"`
+
+	// The setting to use for the compile_multilib property.
+	//
+	// This property is set after optimization so there is no point in trying to optimize it.
+	Compile_multilib string `sdk:"keep"`
 }
 
 // The os prefix to use for any file paths in the sdk.
@@ -500,9 +488,28 @@
 	// Access the base structure.
 	Base() *SdkMemberPropertiesBase
 
-	// Populate the structure with information from the variant.
-	PopulateFromVariant(variant SdkAware)
+	// Populate this structure with information from the variant.
+	PopulateFromVariant(ctx SdkMemberContext, variant Module)
 
-	// Add the information from the structure to the property set.
-	AddToPropertySet(sdkModuleContext ModuleContext, builder SnapshotBuilder, propertySet BpPropertySet)
+	// Add the information from this structure to the property set.
+	AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet)
+}
+
+// Provides access to information common to a specific member.
+type SdkMemberContext interface {
+
+	// The module context of the sdk common os variant which is creating the snapshot.
+	SdkModuleContext() ModuleContext
+
+	// The builder of the snapshot.
+	SnapshotBuilder() SnapshotBuilder
+
+	// The type of the member.
+	MemberType() SdkMemberType
+
+	// The name of the member.
+	//
+	// Provided for use by sdk members to create a member specific location within the snapshot
+	// into which to copy the prebuilt files.
+	Name() 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/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 2778ebd..9b3235c 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -63,9 +63,8 @@
 	return false
 }
 
-func (mt *binarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
-	pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
-	return pbm
+func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
 }
 
 func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
@@ -107,7 +106,7 @@
 	SystemSharedLibs []string
 }
 
-func (p *nativeBinaryInfoProperties) PopulateFromVariant(variant android.SdkAware) {
+func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	ccModule := variant.(*Module)
 
 	p.archType = ccModule.Target().Arch.ArchType.String()
@@ -122,11 +121,12 @@
 	}
 }
 
-func (p *nativeBinaryInfoProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
+func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
 	if p.Compile_multilib != "" {
 		propertySet.AddProperty("compile_multilib", p.Compile_multilib)
 	}
 
+	builder := ctx.SnapshotBuilder()
 	if p.outputFile != nil {
 		propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
 
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/cc_test.go b/cc/cc_test.go
index 56b36df..9a9678f 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2387,6 +2387,17 @@
 	}
 }
 
+func checkEquals(t *testing.T, message string, expected, actual interface{}) {
+	if !reflect.DeepEqual(actual, expected) {
+		t.Errorf(message+
+			"\nactual:   %v"+
+			"\nexpected: %v",
+			actual,
+			expected,
+		)
+	}
+}
+
 func TestLlndkHeaders(t *testing.T) {
 	ctx := testCc(t, `
 	llndk_headers {
@@ -2817,6 +2828,18 @@
 	}
 }
 
+func TestVersioningMacro(t *testing.T) {
+	for _, tc := range []struct{ moduleName, expected string }{
+		{"libc", "__LIBC_API__"},
+		{"libfoo", "__LIBFOO_API__"},
+		{"libfoo@1", "__LIBFOO_1_API__"},
+		{"libfoo-v1", "__LIBFOO_V1_API__"},
+		{"libfoo.v1", "__LIBFOO_V1_API__"},
+	} {
+		checkEquals(t, tc.moduleName, tc.expected, versioningMacroName(tc.moduleName))
+	}
+}
+
 func TestStaticExecutable(t *testing.T) {
 	ctx := testCc(t, `
 		cc_binary {
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 6bd93f9..346e7d8 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -195,6 +195,7 @@
 	module.sdkMemberTypes = []android.SdkMemberType{
 		sharedLibrarySdkMemberType,
 		staticLibrarySdkMemberType,
+		staticAndSharedLibrarySdkMemberType,
 	}
 	return module.Init()
 }
@@ -1329,7 +1330,7 @@
 
 func versioningMacroName(moduleName string) string {
 	macroName := charsNotForMacro.ReplaceAllString(moduleName, "_")
-	macroName = strings.ToUpper(moduleName)
+	macroName = strings.ToUpper(macroName)
 	return "__" + macroName + "_API__"
 }
 
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..4967455 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
 }
 
@@ -96,8 +110,8 @@
 	return false
 }
 
-func (mt *librarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
-	pbm := builder.AddPrebuiltModule(member, mt.prebuiltModuleType)
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, mt.prebuiltModuleType)
 
 	ccModule := member.Variants()[0].(*Module)
 
@@ -322,12 +336,12 @@
 	outputFile android.Path
 }
 
-func (p *nativeLibInfoProperties) PopulateFromVariant(variant android.SdkAware) {
+func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	ccModule := variant.(*Module)
 
 	// 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{}
@@ -352,6 +369,6 @@
 	p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
 }
 
-func (p *nativeLibInfoProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
-	addPossiblyArchSpecificProperties(sdkModuleContext, builder, p, propertySet)
+func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	addPossiblyArchSpecificProperties(ctx.SdkModuleContext(), ctx.SnapshotBuilder(), p, propertySet)
 }
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 7f21721..fc9cc17 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -26,6 +26,7 @@
 	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)
 }
 
@@ -217,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 0eca97f..242d835 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -73,6 +73,15 @@
 				srcs: ["libf.so"],
 			},
 		}
+
+		cc_object {
+			name: "crtx",
+		}
+
+		cc_prebuilt_object {
+			name: "crtx",
+			srcs: ["crtx.o"],
+		}
 	`
 
 	ctx := testPrebuilt(t, bp)
@@ -84,6 +93,7 @@
 	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()
@@ -91,6 +101,7 @@
 	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()
@@ -126,9 +137,14 @@
 	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,
@@ -136,6 +152,7 @@
 		"libe.a":  nil,
 		"libf.a":  nil,
 		"libf.so": nil,
+		"crtx.o":  nil,
 	}
 	config := TestConfig(buildDir, android.Android, nil, bp, fs)
 	ctx := CreateTestContext()
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/droiddoc.go b/java/droiddoc.go
index 1ac7444..b0efaa5 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -2041,18 +2041,33 @@
 	return ok
 }
 
-func (mt *droidStubsSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-	variants := member.Variants()
-	if len(variants) != 1 {
-		sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
+func (mt *droidStubsSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_stubs_sources")
+}
+
+func (mt *droidStubsSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &droidStubsInfoProperties{}
+}
+
+type droidStubsInfoProperties struct {
+	android.SdkMemberPropertiesBase
+
+	StubsSrcJar android.Path
+}
+
+func (p *droidStubsInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	droidstubs := variant.(*Droidstubs)
+	p.StubsSrcJar = droidstubs.stubsSrcJar
+}
+
+func (p *droidStubsInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	if p.StubsSrcJar != nil {
+		builder := ctx.SnapshotBuilder()
+
+		snapshotRelativeDir := filepath.Join("java", ctx.Name()+"_stubs_sources")
+
+		builder.UnzipToSnapshot(p.StubsSrcJar, snapshotRelativeDir)
+
+		propertySet.AddProperty("srcs", []string{snapshotRelativeDir})
 	}
-	variant := variants[0]
-	d, _ := variant.(*Droidstubs)
-	stubsSrcJar := d.stubsSrcJar
-
-	snapshotRelativeDir := filepath.Join("java", d.Name()+"_stubs_sources")
-	builder.UnzipToSnapshot(stubsSrcJar, snapshotRelativeDir)
-
-	pbm := builder.AddPrebuiltModule(member, "prebuilt_stubs_sources")
-	pbm.AddProperty("srcs", []string{snapshotRelativeDir})
 }
diff --git a/java/java.go b/java/java.go
index 3793821..22d14ec 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1862,37 +1862,43 @@
 	return ok
 }
 
-func (mt *librarySdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
-	return builder.AddPrebuiltModule(member, "java_import")
+func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_import")
 }
 
 func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
-	return &librarySdkMemberProperties{memberType: mt}
+	return &librarySdkMemberProperties{}
 }
 
 type librarySdkMemberProperties struct {
 	android.SdkMemberPropertiesBase
 
-	memberType *librarySdkMemberType
-
-	library     *Library
-	jarToExport android.Path
+	JarToExport     android.Path
+	AidlIncludeDirs android.Paths
 }
 
-func (p *librarySdkMemberProperties) PopulateFromVariant(variant android.SdkAware) {
+func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	j := variant.(*Library)
 
-	p.library = j
-	p.jarToExport = p.memberType.jarToExportGetter(j)
+	p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(j)
+	p.AidlIncludeDirs = j.AidlIncludeDirs()
 }
 
-func (p *librarySdkMemberProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
-	if p.jarToExport != nil {
-		exportedJar := p.jarToExport
-		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), p.library.Name())
+func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	builder := ctx.SnapshotBuilder()
+
+	exportedJar := p.JarToExport
+	if exportedJar != nil {
+		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
 		builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
 
-		for _, dir := range p.library.AidlIncludeDirs() {
+		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+	}
+
+	aidlIncludeDirs := p.AidlIncludeDirs
+	if len(aidlIncludeDirs) != 0 {
+		sdkModuleContext := ctx.SdkModuleContext()
+		for _, dir := range aidlIncludeDirs {
 			// TODO(jiyong): copy parcelable declarations only
 			aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
 			for _, file := range aidlFiles {
@@ -1900,7 +1906,7 @@
 			}
 		}
 
-		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+		// TODO(b/151933053) - add aidl include dirs property
 	}
 }
 
@@ -2066,8 +2072,8 @@
 	return ok
 }
 
-func (mt *testSdkMemberType) AddPrebuiltModule(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) android.BpModule {
-	return builder.AddPrebuiltModule(member, "java_test_import")
+func (mt *testSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_test_import")
 }
 
 func (mt *testSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
@@ -2077,11 +2083,11 @@
 type testSdkMemberProperties struct {
 	android.SdkMemberPropertiesBase
 
-	test        *Test
-	jarToExport android.Path
+	JarToExport android.Path
+	TestConfig  android.Path
 }
 
-func (p *testSdkMemberProperties) PopulateFromVariant(variant android.SdkAware) {
+func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
 	test := variant.(*Test)
 
 	implementationJars := test.ImplementationJars()
@@ -2089,19 +2095,25 @@
 		panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name()))
 	}
 
-	p.test = test
-	p.jarToExport = implementationJars[0]
+	p.JarToExport = implementationJars[0]
+	p.TestConfig = test.testConfig
 }
 
-func (p *testSdkMemberProperties) AddToPropertySet(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, propertySet android.BpPropertySet) {
-	if p.jarToExport != nil {
-		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), p.test.Name())
-		builder.CopyToSnapshot(p.jarToExport, snapshotRelativeJavaLibPath)
+func (p *testSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	builder := ctx.SnapshotBuilder()
 
-		snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), p.test.Name(), testConfigSuffix)
-		builder.CopyToSnapshot(p.test.testConfig, snapshotRelativeTestConfigPath)
+	exportedJar := p.JarToExport
+	if exportedJar != nil {
+		snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
+		builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
 
 		propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
+	}
+
+	testConfig := p.TestConfig
+	if testConfig != nil {
+		snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), ctx.Name(), testConfigSuffix)
+		builder.CopyToSnapshot(testConfig, snapshotRelativeTestConfigPath)
 		propertySet.AddProperty("test_config", snapshotRelativeTestConfigPath)
 	}
 }
diff --git a/java/system_modules.go b/java/system_modules.go
index 40031cb..7394fd5 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -242,18 +242,28 @@
 	return false
 }
 
-func (mt *systemModulesSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
-	variants := member.Variants()
-	if len(variants) != 1 {
-		sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
-		for _, variant := range variants {
-			sdkModuleContext.ModuleErrorf("    %q", variant)
-		}
-	}
-	variant := variants[0]
-	systemModule := variant.(*SystemModules)
+func (mt *systemModulesSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+	return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_system_modules_import")
+}
 
-	pbm := builder.AddPrebuiltModule(member, "java_system_modules_import")
-	// Add the references to the libraries that form the system module.
-	pbm.AddPropertyWithTag("libs", systemModule.properties.Libs, builder.SdkMemberReferencePropertyTag(true))
+type systemModulesInfoProperties struct {
+	android.SdkMemberPropertiesBase
+
+	Libs []string
+}
+
+func (mt *systemModulesSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+	return &systemModulesInfoProperties{}
+}
+
+func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	systemModule := variant.(*SystemModules)
+	p.Libs = systemModule.properties.Libs
+}
+
+func (p *systemModulesInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+	if len(p.Libs) > 0 {
+		// Add the references to the libraries that form the system module.
+		propertySet.AddPropertyWithTag("libs", p.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(true))
+	}
 }
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..ca40afd 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 {
@@ -496,6 +553,11 @@
     device_supported: false,
     host_supported: true,
     native_binaries: ["myexports_mynativebinary@current"],
+    target: {
+        windows: {
+            compile_multilib: "64",
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -956,6 +1018,11 @@
     device_supported: false,
     host_supported: true,
     native_shared_libs: ["mysdk_mynativelib@current"],
+    target: {
+        windows: {
+            compile_multilib: "64",
+        },
+    },
 }
 `),
 		checkAllCopyRules(`
@@ -1139,6 +1206,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)
@@ -1214,7 +1368,7 @@
     host_supported: true,
     native_static_libs: ["myexports_mynativelib@current"],
     target: {
-        host: {
+        linux_glibc: {
             compile_multilib: "64",
         },
     },
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 984ed7a..dabdf85 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -52,11 +52,16 @@
 
 	// Information about the OsType specific member variants associated with this variant.
 	//
-	// Set by OsType specific variants when their GenerateAndroidBuildActions is invoked
-	// and used by the CommonOS variant when its GenerateAndroidBuildActions is invoked, which
-	// is guaranteed to occur afterwards.
+	// Set by OsType specific variants in the collectMembers() method and used by the
+	// CommonOS variant when building the snapshot. That work is all done on separate
+	// calls to the sdk.GenerateAndroidBuildActions method which is guaranteed to be
+	// called for the OsType specific variants before the CommonOS variant (because
+	// the latter depends on the former).
 	memberRefs []sdkMemberRef
 
+	// The multilib variants that are used by this sdk variant.
+	multilibUsages multilibUsage
+
 	properties sdkProperties
 
 	snapshotFile android.OptionalPath
@@ -259,8 +264,8 @@
 	// This method is guaranteed to be called on OsType specific variants before it is called
 	// on their corresponding CommonOS variant.
 	if !s.IsCommonOSVariant() {
-		// Collect the OsType specific members are add them to the OsType specific variant.
-		s.memberRefs = s.collectMembers(ctx)
+		// Update the OsType specific sdk variant with information about its members.
+		s.collectMembers(ctx)
 	} else {
 		// Get the OsType specific variants on which the CommonOS depends.
 		osSpecificVariants := android.GetOsSpecificVariantsOfCommonOSVariant(ctx)
diff --git a/sdk/update.go b/sdk/update.go
index d077e40..e14347f 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"
 
@@ -106,9 +107,10 @@
 
 // Collect all the members.
 //
-// Returns a list containing type (extracted from the dependency tag) and the variant.
-func (s *sdk) collectMembers(ctx android.ModuleContext) []sdkMemberRef {
-	var memberRefs []sdkMemberRef
+// Returns a list containing type (extracted from the dependency tag) and the variant
+// plus the multilib usages.
+func (s *sdk) collectMembers(ctx android.ModuleContext) {
+	s.multilibUsages = multilibNone
 	ctx.WalkDeps(func(child android.Module, parent android.Module) bool {
 		tag := ctx.OtherModuleDependencyTag(child)
 		if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
@@ -119,7 +121,10 @@
 				ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName())
 			}
 
-			memberRefs = append(memberRefs, sdkMemberRef{memberType, child.(android.SdkAware)})
+			// Keep track of which multilib variants are used by the sdk.
+			s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType)
+
+			s.memberRefs = append(s.memberRefs, sdkMemberRef{memberType, child.(android.SdkAware)})
 
 			// If the member type supports transitive sdk members then recurse down into
 			// its dependencies, otherwise exit traversal.
@@ -128,8 +133,6 @@
 
 		return false
 	})
-
-	return memberRefs
 }
 
 // Organize the members.
@@ -139,13 +142,10 @@
 // The names are in the order in which the dependencies were added.
 //
 // Returns the members as well as the multilib setting to use.
-func (s *sdk) organizeMembers(ctx android.ModuleContext, memberRefs []sdkMemberRef) ([]*sdkMember, string) {
+func (s *sdk) organizeMembers(ctx android.ModuleContext, memberRefs []sdkMemberRef) []*sdkMember {
 	byType := make(map[android.SdkMemberType][]*sdkMember)
 	byName := make(map[string]*sdkMember)
 
-	lib32 := false // True if any of the members have 32 bit version.
-	lib64 := false // True if any of the members have 64 bit version.
-
 	for _, memberRef := range memberRefs {
 		memberType := memberRef.memberType
 		variant := memberRef.variant
@@ -158,13 +158,6 @@
 			byType[memberType] = append(byType[memberType], member)
 		}
 
-		multilib := variant.Target().Arch.ArchType.Multilib
-		if multilib == "lib32" {
-			lib32 = true
-		} else if multilib == "lib64" {
-			lib64 = true
-		}
-
 		// Only append new variants to the list. This is needed because a member can be both
 		// exported by the sdk and also be a transitive sdk member.
 		member.variants = appendUniqueVariants(member.variants, variant)
@@ -176,17 +169,7 @@
 		members = append(members, membersOfType...)
 	}
 
-	// Compute the setting of multilib.
-	var multilib string
-	if lib32 && lib64 {
-		multilib = "both"
-	} else if lib32 {
-		multilib = "32"
-	} else if lib64 {
-		multilib = "64"
-	}
-
-	return members, multilib
+	return members
 }
 
 func appendUniqueVariants(variants []android.SdkAware, newVariant android.SdkAware) []android.SdkAware {
@@ -266,16 +249,14 @@
 	}
 	s.builderForTests = builder
 
-	members, multilib := s.organizeMembers(ctx, memberRefs)
+	members := s.organizeMembers(ctx, memberRefs)
 	for _, member := range members {
 		memberType := member.memberType
-		prebuiltModule := memberType.AddPrebuiltModule(ctx, builder, member)
-		if prebuiltModule == nil {
-			// Fall back to legacy method of building a snapshot
-			memberType.BuildSnapshot(ctx, builder, member)
-		} else {
-			s.createMemberSnapshot(ctx, builder, member, prebuiltModule)
-		}
+
+		memberCtx := &memberContext{ctx, builder, memberType, member.name}
+
+		prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
+		s.createMemberSnapshot(memberCtx, member, prebuiltModule)
 	}
 
 	// Create a transformer that will transform an unversioned module into a versioned module.
@@ -320,15 +301,6 @@
 
 	addHostDeviceSupportedProperties(s.ModuleBase.DeviceSupported(), s.ModuleBase.HostSupported(), snapshotModule)
 
-	// Compile_multilib defaults to both and must always be set to both on the
-	// device and so only needs to be set when targeted at the host and is neither
-	// unspecified or both.
-	targetPropertySet := snapshotModule.AddPropertySet("target")
-	if s.HostSupported() && multilib != "" && multilib != "both" {
-		hostSet := targetPropertySet.AddPropertySet("host")
-		hostSet.AddProperty("compile_multilib", multilib)
-	}
-
 	var dynamicMemberPropertiesList []interface{}
 	osTypeToMemberProperties := make(map[android.OsType]*sdk)
 	for _, sdkVariant := range sdkVariants {
@@ -346,9 +318,20 @@
 	s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties)
 
 	// Iterate over the os types in a fixed order.
+	targetPropertySet := snapshotModule.AddPropertySet("target")
 	for _, osType := range s.getPossibleOsTypes() {
 		if sdkVariant, ok := osTypeToMemberProperties[osType]; ok {
 			osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name)
+
+			// Compile_multilib defaults to both and must always be set to both on the
+			// device and so only needs to be set when targeted at the host and is neither
+			// unspecified or both.
+			multilib := sdkVariant.multilibUsages
+			if (osType.Class == android.Host || osType.Class == android.HostCross) &&
+				multilib != multilibNone && multilib != multilibBoth {
+				osPropertySet.AddProperty("compile_multilib", multilib.String())
+			}
+
 			s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties)
 		}
 	}
@@ -786,6 +769,47 @@
 	return m.variants
 }
 
+// Track usages of multilib variants.
+type multilibUsage int
+
+const (
+	multilibNone multilibUsage = 0
+	multilib32   multilibUsage = 1
+	multilib64   multilibUsage = 2
+	multilibBoth               = multilib32 | multilib64
+)
+
+// Add the multilib that is used in the arch type.
+func (m multilibUsage) addArchType(archType android.ArchType) multilibUsage {
+	multilib := archType.Multilib
+	switch multilib {
+	case "":
+		return m
+	case "lib32":
+		return m | multilib32
+	case "lib64":
+		return m | multilib64
+	default:
+		panic(fmt.Errorf("Unknown Multilib field in ArchType, expected 'lib32' or 'lib64', found %q", multilib))
+	}
+}
+
+func (m multilibUsage) String() string {
+	switch m {
+	case multilibNone:
+		return ""
+	case multilib32:
+		return "32"
+	case multilib64:
+		return "64"
+	case multilibBoth:
+		return "both"
+	default:
+		panic(fmt.Errorf("Unknown multilib value, found %b, expected one of %b, %b, %b or %b",
+			m, multilibNone, multilib32, multilib64, multilibBoth))
+	}
+}
+
 type baseInfo struct {
 	Properties android.SdkMemberProperties
 }
@@ -793,24 +817,297 @@
 type osTypeSpecificInfo struct {
 	baseInfo
 
+	osType android.OsType
+
 	// 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(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *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.Module)
+	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(ctx, 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(ctx, 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
+	}
+
+	multilib := multilibNone
+	var archPropertiesList []android.SdkMemberProperties
+	for _, archInfo := range osInfo.archInfos {
+		multilib = multilib.addArchType(archInfo.archType)
+
+		// 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.
+	osInfo.Properties.Base().Compile_multilib = multilib.String()
+}
+
+// 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(ctx *memberContext, 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(ctx, 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(ctx, archPropertySet, archOsPrefix)
+	}
+}
+
 type archTypeSpecificInfo struct {
 	baseInfo
 
 	archType android.ArchType
+
+	linkInfos []*linkTypeSpecificInfo
 }
 
-func (s *sdk) createMemberSnapshot(sdkModuleContext android.ModuleContext, builder *snapshotBuilder, member *sdkMember, bpModule android.BpModule) {
+// Create a new archTypeSpecificInfo for the specified arch type and its properties
+// structures populated with information from the variants.
+func newArchSpecificInfo(ctx android.SdkMemberContext, archType android.ArchType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *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(ctx, 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(ctx, 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(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
+	archTypeName := archInfo.archType.Name
+	archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
+	archInfo.Properties.AddToPropertySet(ctx, archTypePropertySet)
+
+	for _, linkInfo := range archInfo.linkInfos {
+		linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
+		linkInfo.Properties.AddToPropertySet(ctx, 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(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *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(ctx, linkVariant)
+	return linkInfo
+}
+
+type memberContext struct {
+	sdkMemberContext android.ModuleContext
+	builder          *snapshotBuilder
+	memberType       android.SdkMemberType
+	name             string
+}
+
+func (m *memberContext) SdkModuleContext() android.ModuleContext {
+	return m.sdkMemberContext
+}
+
+func (m *memberContext) SnapshotBuilder() android.SnapshotBuilder {
+	return m.builder
+}
+
+func (m *memberContext) MemberType() android.SdkMemberType {
+	return m.memberType
+}
+
+func (m *memberContext) Name() string {
+	return m.name
+}
+
+func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) {
 
 	memberType := member.memberType
 
 	// Group the variants by os type.
-	variantsByOsType := make(map[android.OsType][]android.SdkAware)
+	variantsByOsType := make(map[android.OsType][]android.Module)
 	variants := member.Variants()
 	for _, variant := range variants {
 		osType := variant.Target().Os
@@ -839,92 +1136,21 @@
 	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(ctx, osType, variantPropertiesFactory, osTypeVariants)
 		osTypeToInfo[osType] = osInfo
-
-		osSpecificVariantPropertiesFactory := func() android.SdkMemberProperties {
-			properties := variantPropertiesFactory()
-			properties.Base().Os = osType
-			return properties
-		}
-
 		// Add the os specific properties to a list of os type specific yet architecture
 		// independent properties structs.
-		osInfo.Properties = osSpecificVariantPropertiesFactory()
 		osSpecificPropertiesList = append(osSpecificPropertiesList, osInfo.Properties)
 
-		// 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]
-				if len(archVariants) != 1 {
-					panic(fmt.Errorf("expected one arch specific variant but found %d", len(variants)))
-				}
-
-				// 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 = osSpecificVariantPropertiesFactory()
-				archInfo.Properties.PopulateFromVariant(archVariants[0])
-
-				osInfo.archInfos = append(osInfo.archInfos, archInfo)
-			}
-		}
-
-		var archPropertiesList []android.SdkMemberProperties
-		for _, archInfo := range osInfo.archInfos {
-			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
+		// 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.
 	commonValueExtractor.extractCommonProperties(commonProperties, osSpecificPropertiesList)
 
 	// Add the common properties to the module.
-	commonProperties.AddToPropertySet(sdkModuleContext, builder, bpModule)
+	commonProperties.AddToPropertySet(ctx, bpModule)
 
 	// Create a target property set into which target specific properties can be
 	// added.
@@ -937,63 +1163,7 @@
 			continue
 		}
 
-		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>
-			//   }
-			//
-			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 + "_"
-		}
-
-		osInfo.Properties.AddToPropertySet(sdkModuleContext, 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
-		for _, archInfo := range osInfo.archInfos {
-			archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archInfo.archType.Name)
-
-			archInfo.Properties.AddToPropertySet(sdkModuleContext, builder, archTypePropertySet)
-		}
+		osInfo.addToPropertySet(ctx, bpModule, targetPropertySet)
 	}
 }
 
@@ -1113,10 +1283,6 @@
 func (e *commonValueExtractor) extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
 	commonPropertiesValue := reflect.ValueOf(commonProperties)
 	commonStructValue := commonPropertiesValue.Elem()
-	propertiesStructType := commonStructValue.Type()
-
-	// Create an empty structure from which default values for the field can be copied.
-	emptyStructValue := reflect.New(propertiesStructType).Elem()
 
 	for _, fieldGetter := range e.fieldGetters {
 		// Check to see if all the structures have the same value for the field. The commonValue
@@ -1145,7 +1311,7 @@
 		// If the fields all have a common value then store it in the common struct field
 		// and set the input struct's field to the empty value.
 		if commonValue != nil {
-			emptyValue := fieldGetter(emptyStructValue)
+			emptyValue := reflect.Zero(commonValue.Type())
 			fieldGetter(commonStructValue).Set(*commonValue)
 			for i := 0; i < sliceValue.Len(); i++ {
 				itemValue := sliceValue.Index(i)
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
+}