Merge "Add support for selects on string lists" into main
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
index ebca413..9f399bf 100644
--- a/aconfig/codegen/java_aconfig_library.go
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -72,7 +72,7 @@
 		module.AddSharedLibrary("aconfig-annotations-lib")
 		// TODO(b/303773055): Remove the annotation after access issue is resolved.
 		module.AddSharedLibrary("unsupportedappusage")
-		module.AddSharedLibrary("aconfig_storage_reader_java")
+		module.AddSharedLibrary("aconfig_storage_stub")
 	}
 }
 
diff --git a/android/Android.bp b/android/Android.bp
index a9a3564..dfea8f9 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -111,6 +111,7 @@
         "testing.go",
         "util.go",
         "variable.go",
+        "vendor_api_levels.go",
         "vintf_fragment.go",
         "vintf_data.go",
         "visibility.go",
diff --git a/android/apex.go b/android/apex.go
index 414d4e1..db93912 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"reflect"
 	"slices"
 	"sort"
 	"strconv"
@@ -62,14 +61,6 @@
 	// that are merged together.
 	InApexVariants []string
 
-	// List of APEX Soong module names that this module is part of. Note that the list includes
-	// different variations of the same APEX. For example, if module `foo` is included in the
-	// apex `com.android.foo`, and also if there is an override_apex module
-	// `com.mycompany.android.foo` overriding `com.android.foo`, then this list contains both
-	// `com.android.foo` and `com.mycompany.android.foo`.  If the APEX Soong module is a
-	// prebuilt, the name here doesn't have the `prebuilt_` prefix.
-	InApexModules []string
-
 	// True if this is for a prebuilt_apex.
 	//
 	// If true then this will customize the apex processing to make it suitable for handling
@@ -100,7 +91,6 @@
 	(*d)["Apex"] = map[string]interface{}{
 		"ApexVariationName": i.ApexVariationName,
 		"MinSdkVersion":     i.MinSdkVersion,
-		"InApexModules":     i.InApexModules,
 		"InApexVariants":    i.InApexVariants,
 		"ForPrebuiltApex":   i.ForPrebuiltApex,
 	}
@@ -135,15 +125,6 @@
 	return false
 }
 
-func (i ApexInfo) InApexModule(apexModuleName string) bool {
-	for _, a := range i.InApexModules {
-		if a == apexModuleName {
-			return true
-		}
-	}
-	return false
-}
-
 // To satisfy the comparable interface
 func (i ApexInfo) Equal(other any) bool {
 	otherApexInfo, ok := other.(ApexInfo)
@@ -151,8 +132,7 @@
 		i.MinSdkVersion == otherApexInfo.MinSdkVersion &&
 		i.Updatable == otherApexInfo.Updatable &&
 		i.UsePlatformApis == otherApexInfo.UsePlatformApis &&
-		reflect.DeepEqual(i.InApexVariants, otherApexInfo.InApexVariants) &&
-		reflect.DeepEqual(i.InApexModules, otherApexInfo.InApexModules)
+		slices.Equal(i.InApexVariants, otherApexInfo.InApexVariants)
 }
 
 // ApexBundleInfo contains information about the dependencies of an apex
@@ -272,9 +252,6 @@
 	// Default is ["//apex_available:platform"].
 	Apex_available []string
 
-	// See ApexModule.InAnyApex()
-	InAnyApex bool `blueprint:"mutated"`
-
 	// See ApexModule.NotAvailableForPlatform()
 	NotAvailableForPlatform bool `blueprint:"mutated"`
 
@@ -361,30 +338,22 @@
 func (m *ApexModuleBase) BuildForApex(apex ApexInfo) {
 	m.apexInfosLock.Lock()
 	defer m.apexInfosLock.Unlock()
-	for i, v := range m.apexInfos {
-		if v.ApexVariationName == apex.ApexVariationName {
-			if len(apex.InApexModules) != 1 {
-				panic(fmt.Errorf("Newly created apexInfo must be for a single APEX"))
-			}
-			// Even when the ApexVariantNames are the same, the given ApexInfo might
-			// actually be for different APEX. This can happen when an APEX is
-			// overridden via override_apex. For example, there can be two apexes
-			// `com.android.foo` (from the `apex` module type) and
-			// `com.mycompany.android.foo` (from the `override_apex` module type), both
-			// of which has the same ApexVariantName `com.android.foo`. Add the apex
-			// name to the list so that it's not lost.
-			if !InList(apex.InApexModules[0], v.InApexModules) {
-				m.apexInfos[i].InApexModules = append(m.apexInfos[i].InApexModules, apex.InApexModules[0])
-			}
-			return
-		}
+	if slices.ContainsFunc(m.apexInfos, func(existing ApexInfo) bool {
+		return existing.ApexVariationName == apex.ApexVariationName
+	}) {
+		return
 	}
 	m.apexInfos = append(m.apexInfos, apex)
 }
 
 // Implements ApexModule
 func (m *ApexModuleBase) InAnyApex() bool {
-	return m.ApexProperties.InAnyApex
+	for _, apex_name := range m.ApexProperties.Apex_available {
+		if apex_name != AvailableToPlatform {
+			return true
+		}
+	}
+	return false
 }
 
 // Implements ApexModule
@@ -546,7 +515,6 @@
 		if index, exists := seen[mergedName]; exists {
 			// Variants having the same mergedName are deduped
 			merged[index].InApexVariants = append(merged[index].InApexVariants, variantName)
-			merged[index].InApexModules = append(merged[index].InApexModules, apexInfo.InApexModules...)
 			merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
 			// Platform APIs is allowed for this module only when all APEXes containing
 			// the module are with `use_platform_apis: true`.
@@ -556,7 +524,6 @@
 			seen[mergedName] = len(merged)
 			apexInfo.ApexVariationName = mergedName
 			apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants)
-			apexInfo.InApexModules = CopyOf(apexInfo.InApexModules)
 			apexInfo.TestApexes = CopyOf(apexInfo.TestApexes)
 			merged = append(merged, apexInfo)
 		}
@@ -644,8 +611,6 @@
 		apexInfos, _ = mergeApexVariations(apexInfos)
 	}
 
-	base.ApexProperties.InAnyApex = true
-
 	if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && module.NotAvailableForPlatform() {
 		// Do not install the module for platform, but still allow it to output
 		// uninstallable AndroidMk entries in certain cases when they have side
diff --git a/android/apex_test.go b/android/apex_test.go
index 347bf7d..78597b2 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -37,7 +37,6 @@
 					ApexVariationName: "foo",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo"},
-					InApexModules:     []string{"foo"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -46,7 +45,6 @@
 					ApexVariationName: "apex10000",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo"},
-					InApexModules:     []string{"foo"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -61,14 +59,12 @@
 					ApexVariationName: "foo",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo"},
-					InApexModules:     []string{"foo"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 				{
 					ApexVariationName: "bar",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"bar"},
-					InApexModules:     []string{"bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -77,7 +73,6 @@
 					ApexVariationName: "apex10000",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo", "bar"},
-					InApexModules:     []string{"foo", "bar"},
 				}},
 			wantAliases: [][2]string{
 				{"foo", "apex10000"},
@@ -91,14 +86,12 @@
 					ApexVariationName: "foo",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo"},
-					InApexModules:     []string{"foo"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 				{
 					ApexVariationName: "bar",
 					MinSdkVersion:     uncheckedFinalApiLevel(30),
 					InApexVariants:    []string{"bar"},
-					InApexModules:     []string{"bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -107,14 +100,12 @@
 					ApexVariationName: "apex10000",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo"},
-					InApexModules:     []string{"foo"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 				{
 					ApexVariationName: "apex30",
 					MinSdkVersion:     uncheckedFinalApiLevel(30),
 					InApexVariants:    []string{"bar"},
-					InApexModules:     []string{"bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -130,7 +121,6 @@
 					ApexVariationName: "foo",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo"},
-					InApexModules:     []string{"foo"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 				{
@@ -138,7 +128,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					Updatable:         true,
 					InApexVariants:    []string{"bar"},
-					InApexModules:     []string{"bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -148,7 +137,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					Updatable:         true,
 					InApexVariants:    []string{"foo", "bar"},
-					InApexModules:     []string{"foo", "bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -164,7 +152,6 @@
 					ApexVariationName: "foo",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo"},
-					InApexModules:     []string{"foo"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 				{
@@ -172,7 +159,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					Updatable:         true,
 					InApexVariants:    []string{"bar"},
-					InApexModules:     []string{"bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 				// This one should not be merged in with the others because it is for
@@ -182,7 +168,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					Updatable:         true,
 					InApexVariants:    []string{"baz"},
-					InApexModules:     []string{"baz"},
 					ForPrebuiltApex:   ForPrebuiltApex,
 				},
 			},
@@ -192,7 +177,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					Updatable:         true,
 					InApexVariants:    []string{"foo", "bar"},
-					InApexModules:     []string{"foo", "bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 				{
@@ -200,7 +184,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					Updatable:         true,
 					InApexVariants:    []string{"baz"},
-					InApexModules:     []string{"baz"},
 					ForPrebuiltApex:   ForPrebuiltApex,
 				},
 			},
@@ -216,7 +199,6 @@
 					ApexVariationName: "foo",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo"},
-					InApexModules:     []string{"foo"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 				{
@@ -224,7 +206,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					UsePlatformApis:   true,
 					InApexVariants:    []string{"bar"},
-					InApexModules:     []string{"bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -233,7 +214,6 @@
 					ApexVariationName: "apex10000",
 					MinSdkVersion:     FutureApiLevel,
 					InApexVariants:    []string{"foo", "bar"},
-					InApexModules:     []string{"foo", "bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -250,7 +230,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					UsePlatformApis:   true,
 					InApexVariants:    []string{"foo"},
-					InApexModules:     []string{"foo"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 				{
@@ -258,7 +237,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					UsePlatformApis:   true,
 					InApexVariants:    []string{"bar"},
-					InApexModules:     []string{"bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
@@ -268,7 +246,6 @@
 					MinSdkVersion:     FutureApiLevel,
 					UsePlatformApis:   true,
 					InApexVariants:    []string{"foo", "bar"},
-					InApexModules:     []string{"foo", "bar"},
 					ForPrebuiltApex:   NotForPrebuiltApex,
 				},
 			},
diff --git a/android/container.go b/android/container.go
index 2a3777b..27b17ed 100644
--- a/android/container.go
+++ b/android/container.go
@@ -93,7 +93,7 @@
 
 	// TODO(b/363016634): Remove from the allowlist when the module is converted
 	// to java_sdk_library and the java_aconfig_library modules depend on the stub.
-	"aconfig_storage_reader_java",
+	"aconfig_storage_stub",
 
 	// framework-res provides core resources essential for building apps and system UI.
 	// This module is implicitly added as a dependency for java modules even when the
@@ -382,7 +382,7 @@
 
 func (c *ContainersInfo) ApexNames() (ret []string) {
 	for _, apex := range c.belongingApexes {
-		ret = append(ret, apex.InApexModules...)
+		ret = append(ret, apex.InApexVariants...)
 	}
 	slices.Sort(ret)
 	return ret
diff --git a/android/test_config.go b/android/test_config.go
index f251038..3609e6b 100644
--- a/android/test_config.go
+++ b/android/test_config.go
@@ -45,6 +45,7 @@
 			Platform_version_active_codenames:   []string{"S", "Tiramisu"},
 			DeviceSystemSdkVersions:             []string{"29", "30", "S"},
 			Platform_systemsdk_versions:         []string{"29", "30", "S", "Tiramisu"},
+			VendorApiLevel:                      stringPtr("202404"),
 			AAPTConfig:                          []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
 			AAPTPreferredConfig:                 stringPtr("xhdpi"),
 			AAPTCharacteristics:                 stringPtr("nosdcard"),
diff --git a/android/variable.go b/android/variable.go
index e666530..36ddc1c 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -613,20 +613,22 @@
 	VendorSecurityPatch string `json:",omitempty"`
 
 	// Boot image stuff
-	BuildingRamdiskImage            bool   `json:",omitempty"`
-	ProductBuildBootImage           bool   `json:",omitempty"`
-	ProductBuildVendorBootImage     string `json:",omitempty"`
-	ProductBuildInitBootImage       bool   `json:",omitempty"`
-	BoardUsesRecoveryAsBoot         bool   `json:",omitempty"`
-	BoardPrebuiltBootimage          string `json:",omitempty"`
-	BoardPrebuiltInitBootimage      string `json:",omitempty"`
-	BoardBootimagePartitionSize     string `json:",omitempty"`
-	BoardInitBootimagePartitionSize string `json:",omitempty"`
-	BoardBootHeaderVersion          string `json:",omitempty"`
-	TargetKernelPath                string `json:",omitempty"`
-	BoardUsesGenericKernelImage     bool   `json:",omitempty"`
-	BootSecurityPatch               string `json:",omitempty"`
-	InitBootSecurityPatch           string `json:",omitempty"`
+	BuildingRamdiskImage            bool     `json:",omitempty"`
+	ProductBuildBootImage           bool     `json:",omitempty"`
+	ProductBuildVendorBootImage     string   `json:",omitempty"`
+	ProductBuildInitBootImage       bool     `json:",omitempty"`
+	BoardUsesRecoveryAsBoot         bool     `json:",omitempty"`
+	BoardPrebuiltBootimage          string   `json:",omitempty"`
+	BoardPrebuiltInitBootimage      string   `json:",omitempty"`
+	BoardBootimagePartitionSize     string   `json:",omitempty"`
+	BoardInitBootimagePartitionSize string   `json:",omitempty"`
+	BoardBootHeaderVersion          string   `json:",omitempty"`
+	TargetKernelPath                string   `json:",omitempty"`
+	BoardUsesGenericKernelImage     bool     `json:",omitempty"`
+	BootSecurityPatch               string   `json:",omitempty"`
+	InitBootSecurityPatch           string   `json:",omitempty"`
+	BoardIncludeDtbInBootimg        bool     `json:",omitempty"`
+	InternalKernelCmdline           []string `json:",omitempty"`
 
 	// Avb (android verified boot) stuff
 	BoardAvbEnable          bool                                `json:",omitempty"`
diff --git a/android/vendor_api_levels.go b/android/vendor_api_levels.go
new file mode 100644
index 0000000..4d364fd
--- /dev/null
+++ b/android/vendor_api_levels.go
@@ -0,0 +1,49 @@
+// Copyright 2024 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"fmt"
+	"strconv"
+)
+
+func getSdkVersionOfVendorApiLevel(apiLevel int) (int, bool) {
+	ok := true
+	sdkVersion := -1
+	switch apiLevel {
+	case 202404:
+		sdkVersion = 35
+	case 202504:
+		sdkVersion = 36
+	default:
+		ok = false
+	}
+	return sdkVersion, ok
+}
+
+func GetSdkVersionForVendorApiLevel(vendorApiLevel string) (ApiLevel, error) {
+	vendorApiLevelInt, err := strconv.Atoi(vendorApiLevel)
+	if err != nil {
+		return NoneApiLevel, fmt.Errorf("The vendor API level %q must be able to be parsed as an integer", vendorApiLevel)
+	}
+	if vendorApiLevelInt < 35 {
+		return uncheckedFinalApiLevel(vendorApiLevelInt), nil
+	}
+
+	if sdkInt, ok := getSdkVersionOfVendorApiLevel(vendorApiLevelInt); ok {
+		return uncheckedFinalApiLevel(sdkInt), nil
+	}
+	return NoneApiLevel, fmt.Errorf("Unknown vendor API level %q. Requires updating the map in vendor_api_level.go?", vendorApiLevel)
+}
diff --git a/apex/apex.go b/apex/apex.go
index ed9e58a..0b56bf8 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1020,7 +1020,6 @@
 		Updatable:         a.Updatable(),
 		UsePlatformApis:   a.UsePlatformApis(),
 		InApexVariants:    []string{apexVariationName},
-		InApexModules:     []string{a.Name()}, // could be com.mycompany.android.foo
 		TestApexes:        testApexes,
 		BaseApexName:      mctx.ModuleName(),
 		ApexAvailableName: proptools.String(a.properties.Apex_available_name),
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 2bef0cc..f93eada 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -356,7 +356,6 @@
 	apexInfo := android.ApexInfo{
 		ApexVariationName: apexVariationName,
 		InApexVariants:    []string{apexVariationName},
-		InApexModules:     []string{p.BaseModuleName()}, // BaseModuleName() to avoid the prebuilt_ prefix.
 		ForPrebuiltApex:   true,
 	}
 
diff --git a/bpf/libbpf/libbpf_prog.go b/bpf/libbpf/libbpf_prog.go
index 18e03a5..3b26d46 100644
--- a/bpf/libbpf/libbpf_prog.go
+++ b/bpf/libbpf/libbpf_prog.go
@@ -158,7 +158,8 @@
 		"-Wall",
 		"-Werror",
 		"-Wextra",
-
+		// Flag to assist with the transition to libbpf
+		"-DENABLE_LIBBPF",
 		"-isystem bionic/libc/include",
 		"-isystem bionic/libc/kernel/uapi",
 		// The architecture doesn't matter here, but asm/types.h is included by linux/types.h.
diff --git a/cc/api_level.go b/cc/api_level.go
index 69a0d3a..3dac571 100644
--- a/cc/api_level.go
+++ b/cc/api_level.go
@@ -41,12 +41,25 @@
 	}
 }
 
+// Native API levels cannot be less than the MinApiLevelForArch. This function
+// sets the lower bound of the API level with the MinApiLevelForArch.
+func nativeClampedApiLevel(ctx android.BaseModuleContext,
+	apiLevel android.ApiLevel) android.ApiLevel {
+
+	min := MinApiForArch(ctx, ctx.Arch().ArchType)
+
+	if apiLevel.LessThan(min) {
+		return min
+	}
+
+	return apiLevel
+}
+
 func nativeApiLevelFromUser(ctx android.BaseModuleContext,
 	raw string) (android.ApiLevel, error) {
 
-	min := MinApiForArch(ctx, ctx.Arch().ArchType)
 	if raw == "minimum" {
-		return min, nil
+		return MinApiForArch(ctx, ctx.Arch().ArchType), nil
 	}
 
 	value, err := android.ApiLevelFromUser(ctx, raw)
@@ -54,15 +67,12 @@
 		return android.NoneApiLevel, err
 	}
 
-	if value.LessThan(min) {
-		return min, nil
-	}
-
-	return value, nil
+	return nativeClampedApiLevel(ctx, value), nil
 }
 
 func nativeApiLevelOrPanic(ctx android.BaseModuleContext,
 	raw string) android.ApiLevel {
+
 	value, err := nativeApiLevelFromUser(ctx, raw)
 	if err != nil {
 		panic(err.Error())
diff --git a/cc/builder.go b/cc/builder.go
index 2948ca3..b98bef9 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -945,7 +945,7 @@
 func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path,
 	baseName string, exportedIncludeDirs []string, symbolFile android.OptionalPath,
 	excludedSymbolVersions, excludedSymbolTags, includedSymbolTags []string,
-	api string, isLlndk bool) android.Path {
+	api string) android.Path {
 
 	outputFile := android.PathForModuleOut(ctx, baseName+".lsdump")
 
@@ -966,9 +966,6 @@
 	for _, tag := range includedSymbolTags {
 		symbolFilterStr += " --include-symbol-tag " + tag
 	}
-	if isLlndk {
-		symbolFilterStr += " --symbol-tag-policy MatchTagOnly"
-	}
 	apiLevelsJson := android.GetApiLevelsJson(ctx)
 	implicits = append(implicits, apiLevelsJson)
 	symbolFilterStr += " --api-map " + apiLevelsJson.String()
diff --git a/cc/cc.go b/cc/cc.go
index bd91964..65ab686 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -341,15 +341,14 @@
 	// If true, always create an sdk variant and don't create a platform variant.
 	Sdk_variant_only *bool
 
-	AndroidMkSharedLibs       []string `blueprint:"mutated"`
-	AndroidMkStaticLibs       []string `blueprint:"mutated"`
-	AndroidMkRlibs            []string `blueprint:"mutated"`
-	AndroidMkRuntimeLibs      []string `blueprint:"mutated"`
-	AndroidMkWholeStaticLibs  []string `blueprint:"mutated"`
-	AndroidMkHeaderLibs       []string `blueprint:"mutated"`
-	HideFromMake              bool     `blueprint:"mutated"`
-	PreventInstall            bool     `blueprint:"mutated"`
-	ApexesProvidingSharedLibs []string `blueprint:"mutated"`
+	AndroidMkSharedLibs      []string `blueprint:"mutated"`
+	AndroidMkStaticLibs      []string `blueprint:"mutated"`
+	AndroidMkRlibs           []string `blueprint:"mutated"`
+	AndroidMkRuntimeLibs     []string `blueprint:"mutated"`
+	AndroidMkWholeStaticLibs []string `blueprint:"mutated"`
+	AndroidMkHeaderLibs      []string `blueprint:"mutated"`
+	HideFromMake             bool     `blueprint:"mutated"`
+	PreventInstall           bool     `blueprint:"mutated"`
 
 	// Set by DepsMutator.
 	AndroidMkSystemSharedLibs []string `blueprint:"mutated"`
@@ -1880,7 +1879,7 @@
 // Returns true if a stub library could be installed in multiple apexes
 func (c *Module) stubLibraryMultipleApexViolation(ctx android.ModuleContext) bool {
 	// If this is not an apex variant, no check necessary
-	if !c.InAnyApex() {
+	if info, ok := android.ModuleProvider(ctx, android.ApexInfoProvider); !ok || info.IsForPlatform() {
 		return false
 	}
 	// If this is not a stub library, no check necessary
@@ -3285,18 +3284,6 @@
 				c.Properties.AndroidMkHeaderLibs = append(
 					c.Properties.AndroidMkHeaderLibs, makeLibName)
 			case libDepTag.shared():
-				if lib := moduleLibraryInterface(dep); lib != nil {
-					if lib.buildStubs() && dep.(android.ApexModule).InAnyApex() {
-						// Add the dependency to the APEX(es) providing the library so that
-						// m <module> can trigger building the APEXes as well.
-						depApexInfo, _ := android.OtherModuleProvider(ctx, dep, android.ApexInfoProvider)
-						for _, an := range depApexInfo.InApexVariants {
-							c.Properties.ApexesProvidingSharedLibs = append(
-								c.Properties.ApexesProvidingSharedLibs, an)
-						}
-					}
-				}
-
 				// Note: the order of libs in this list is not important because
 				// they merely serve as Make dependencies and do not affect this lib itself.
 				c.Properties.AndroidMkSharedLibs = append(
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 144b90b..98af7b6 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -40,9 +40,6 @@
 
 var prepareForCcTest = android.GroupFixturePreparers(
 	PrepareForIntegrationTestWithCc,
-	android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-		variables.VendorApiLevel = StringPtr("202404")
-	}),
 )
 
 var apexVariationName = "apex28"
@@ -1008,7 +1005,7 @@
 	android.AssertArrayString(t, "variants for llndk stubs", expected, actual)
 
 	params := result.ModuleForTests("libllndk", "android_vendor_arm_armv7-a-neon_shared").Description("generate stub")
-	android.AssertSame(t, "use Vendor API level for default stubs", "999999", params.Args["apiLevel"])
+	android.AssertSame(t, "use Vendor API level for default stubs", "35", params.Args["apiLevel"])
 
 	checkExportedIncludeDirs := func(module, variant string, expectedSystemDirs []string, expectedDirs ...string) {
 		t.Helper()
diff --git a/cc/config/global.go b/cc/config/global.go
index 6984ea4..27aac95 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -296,6 +296,7 @@
 
 		// Allow using VLA CXX extension.
 		"-Wno-vla-cxx-extension",
+		"-Wno-cast-function-type-mismatch",
 	}
 
 	noOverride64GlobalCflags = []string{}
@@ -384,7 +385,7 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r530567"
+	ClangDefaultVersion      = "clang-r536225"
 	ClangDefaultShortVersion = "19"
 
 	// Directories with warnings from Android.bp files.
diff --git a/cc/library.go b/cc/library.go
index 23ee9b1..ea87946 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -566,10 +566,16 @@
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	if ctx.IsLlndk() {
-		futureVendorApiLevel := android.ApiLevelOrPanic(ctx, "999999")
+		// Get the matching SDK version for the vendor API level.
+		version, err := android.GetSdkVersionForVendorApiLevel(ctx.Config().VendorApiLevel())
+		if err != nil {
+			panic(err)
+		}
+
+		// This is the vendor variant of an LLNDK library, build the LLNDK stubs.
 		nativeAbiResult := parseNativeAbiDefinition(ctx,
 			String(library.Properties.Llndk.Symbol_file),
-			futureVendorApiLevel, "--llndk")
+			nativeClampedApiLevel(ctx, version), "--llndk")
 		objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
 		if !Bool(library.Properties.Llndk.Unversioned) {
 			library.versionScriptPath = android.OptionalPathForPath(
@@ -1285,15 +1291,14 @@
 func (library *libraryDecorator) linkLlndkSAbiDumpFiles(ctx ModuleContext,
 	deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string,
 	excludeSymbolVersions, excludeSymbolTags []string,
-	vendorApiLevel string) android.Path {
-	// NDK symbols in version 34 are LLNDK symbols. Those in version 35 are not.
+	sdkVersionForVendorApiLevel string) android.Path {
 	return transformDumpToLinkedDump(ctx,
 		sAbiDumpFiles, soFile, libFileName+".llndk",
 		library.llndkIncludeDirsForAbiCheck(ctx, deps),
 		android.OptionalPathForModuleSrc(ctx, library.Properties.Llndk.Symbol_file),
 		append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...),
 		append([]string{"platform-only"}, excludeSymbolTags...),
-		[]string{"llndk=" + vendorApiLevel}, "34", true /* isLlndk */)
+		[]string{"llndk"}, sdkVersionForVendorApiLevel)
 }
 
 func (library *libraryDecorator) linkApexSAbiDumpFiles(ctx ModuleContext,
@@ -1306,7 +1311,7 @@
 		android.OptionalPathForModuleSrc(ctx, library.Properties.Stubs.Symbol_file),
 		append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...),
 		append([]string{"platform-only"}, excludeSymbolTags...),
-		[]string{"apex", "systemapi"}, sdkVersion, false /* isLlndk */)
+		[]string{"apex", "systemapi"}, sdkVersion)
 }
 
 func getRefAbiDumpFile(ctx android.ModuleInstallPathContext,
@@ -1444,7 +1449,7 @@
 			android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)),
 			headerAbiChecker.Exclude_symbol_versions,
 			headerAbiChecker.Exclude_symbol_tags,
-			[]string{} /* includeSymbolTags */, currSdkVersion, false /* isLlndk */)
+			[]string{} /* includeSymbolTags */, currSdkVersion)
 
 		var llndkDump, apexVariantDump android.Path
 		tags := classifySourceAbiDump(ctx.Module().(*Module))
@@ -1452,12 +1457,17 @@
 		for _, tag := range tags {
 			if tag == llndkLsdumpTag && currVendorVersion != "" {
 				if llndkDump == nil {
+					sdkVersion, err := android.GetSdkVersionForVendorApiLevel(currVendorVersion)
+					if err != nil {
+						ctx.ModuleErrorf("Cannot create %s llndk dump: %s", fileName, err)
+						return
+					}
 					// TODO(b/323447559): Evaluate if replacing sAbiDumpFiles with implDump is faster
 					llndkDump = library.linkLlndkSAbiDumpFiles(ctx,
 						deps, objs.sAbiDumpFiles, soFile, fileName,
 						headerAbiChecker.Exclude_symbol_versions,
 						headerAbiChecker.Exclude_symbol_tags,
-						currVendorVersion)
+						nativeClampedApiLevel(ctx, sdkVersion).String())
 				}
 				addLsdumpPath(ctx.Config(), string(tag)+":"+llndkDump.String())
 			} else if tag == apexLsdumpTag {
diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py
index 22f31d9..6c24b4f 100755
--- a/cc/ndkstubgen/test_ndkstubgen.py
+++ b/cc/ndkstubgen/test_ndkstubgen.py
@@ -473,16 +473,17 @@
             VERSION_35 { # introduced=35
                 global:
                     wiggle;
-                    waggle;
-                    waggle; # llndk=202404
-                    bubble; # llndk=202404
-                    duddle;
-                    duddle; # llndk=202504
+                    waggle; # llndk
             } VERSION_34;
+            VERSION_36 { # introduced=36
+                global:
+                    abc;
+                    xyz; # llndk
+            } VERSION_35;
         """))
         f = copy(self.filter)
         f.llndk = True
-        f.api = 202404
+        f.api = 35
         parser = symbolfile.SymbolFileParser(input_file, {}, f)
         versions = parser.parse()
 
@@ -497,8 +498,8 @@
         expected_src = textwrap.dedent("""\
             void foo() {}
             void bar() {}
+            void wiggle() {}
             void waggle() {}
-            void bubble() {}
         """)
         self.assertEqual(expected_src, src_file.getvalue())
 
@@ -510,8 +511,8 @@
             };
             VERSION_35 {
                 global:
+                    wiggle;
                     waggle;
-                    bubble;
             } VERSION_34;
         """)
         self.assertEqual(expected_version, version_file.getvalue())
@@ -521,15 +522,15 @@
             LIBANDROID {
                 global:
                     foo; # introduced=34
-                    bar; # introduced=35
-                    bar; # llndk=202404
-                    baz; # introduced=35
+                    bar; # introduced=35 llndk
+                    baz; # introduced=V
+                    qux; # introduced=36
             };
         """))
         f = copy(self.filter)
         f.llndk = True
-        f.api = 202404
-        parser = symbolfile.SymbolFileParser(input_file, {}, f)
+        f.api = 35
+        parser = symbolfile.SymbolFileParser(input_file, {'V': 35}, f)
         versions = parser.parse()
 
         src_file = io.StringIO()
@@ -543,6 +544,7 @@
         expected_src = textwrap.dedent("""\
             void foo() {}
             void bar() {}
+            void baz() {}
         """)
         self.assertEqual(expected_src, src_file.getvalue())
 
@@ -551,6 +553,7 @@
                 global:
                     foo;
                     bar;
+                    baz;
             };
         """)
         self.assertEqual(expected_version, version_file.getvalue())
diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py
index 4553616..f2bd186 100644
--- a/cc/symbolfile/__init__.py
+++ b/cc/symbolfile/__init__.py
@@ -103,24 +103,13 @@
     @property
     def has_llndk_tags(self) -> bool:
         """Returns True if any LL-NDK tags are set."""
-        for tag in self.tags:
-            if tag == 'llndk' or tag.startswith('llndk='):
-                return True
-        return False
+        return 'llndk' in self.tags
 
     @property
     def has_platform_only_tags(self) -> bool:
         """Returns True if any platform-only tags are set."""
         return 'platform-only' in self.tags
 
-    def copy_introduced_from(self, tags: Tags) -> None:
-        """Copies introduced= or introduced-*= tags."""
-        for tag in tags:
-            if tag.startswith('introduced=') or tag.startswith('introduced-'):
-                name, _ = split_tag(tag)
-                if not any(self_tag.startswith(name + '=') for self_tag in self.tags):
-                    self.tags += (tag,)
-
 
 @dataclass
 class Symbol:
@@ -158,8 +147,6 @@
     """Returns true if this tag has an API level that may need decoding."""
     if tag.startswith('llndk-deprecated='):
         return True
-    if tag.startswith('llndk='):
-        return True
     if tag.startswith('introduced='):
         return True
     if tag.startswith('introduced-'):
@@ -245,21 +232,19 @@
         self.systemapi = systemapi
         self.ndk = ndk
 
+    def _symbol_in_arch_api(self, tags: Tags) -> bool:
+        if not symbol_in_arch(tags, self.arch):
+            return True
+        if not symbol_in_api(tags, self.arch, self.api):
+            return True
+        return False
+
     def _should_omit_tags(self, tags: Tags) -> bool:
         """Returns True if the tagged object should be omitted.
 
         This defines the rules shared between version tagging and symbol tagging.
         """
-        # LLNDK mode/tags follow the similar filtering except that API level checking
-        # is based llndk= instead of introduced=.
-        if self.llndk:
-            if tags.has_mode_tags and not tags.has_llndk_tags:
-                return True
-            if not symbol_in_arch(tags, self.arch):
-                return True
-            if not symbol_in_llndk_api(tags, self.arch, self.api):
-                return True
-            return False
+        # The apex and llndk tags will only exclude APIs from other modes. If in
         # APEX or LLNDK mode and neither tag is provided, we fall back to the
         # default behavior because all NDK symbols are implicitly available to
         # APEX and LLNDK.
@@ -268,12 +253,10 @@
                 return False
             if self.systemapi and tags.has_systemapi_tags:
                 return False
+            if self.llndk and tags.has_llndk_tags:
+                return self._symbol_in_arch_api(tags)
             return True
-        if not symbol_in_arch(tags, self.arch):
-            return True
-        if not symbol_in_api(tags, self.arch, self.api):
-            return True
-        return False
+        return self._symbol_in_arch_api(tags)
 
     def should_omit_version(self, version: Version) -> bool:
         """Returns True if the version section should be omitted.
@@ -286,10 +269,6 @@
             return True
         if version.tags.has_platform_only_tags:
             return True
-        # Include all versions when targeting LLNDK because LLNDK symbols are self-versioned.
-        # Empty version block will be handled separately.
-        if self.llndk:
-            return False
         return self._should_omit_tags(version.tags)
 
     def should_omit_symbol(self, symbol: Symbol) -> bool:
@@ -302,6 +281,7 @@
 
         return self._should_omit_tags(symbol.tags)
 
+
 def symbol_in_arch(tags: Tags, arch: Arch) -> bool:
     """Returns true if the symbol is present for the given architecture."""
     has_arch_tags = False
@@ -316,14 +296,6 @@
     # for the tagged architectures.
     return not has_arch_tags
 
-def symbol_in_llndk_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool:
-    """Returns true if the symbol is present for the given LLNDK API level."""
-    # Check llndk= first.
-    for tag in tags:
-        if tag.startswith('llndk='):
-            return api >= int(get_tag_value(tag))
-    # If not, we keep old behavior: NDK symbols in <= 34 are LLNDK symbols.
-    return symbol_in_api(tags, arch, 34)
 
 def symbol_in_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool:
     """Returns true if the symbol is present for the given API level."""
@@ -400,7 +372,6 @@
                     f'Unexpected contents at top level: {self.current_line}')
 
         self.check_no_duplicate_symbols(versions)
-        self.check_llndk_introduced(versions)
         return versions
 
     def check_no_duplicate_symbols(self, versions: Iterable[Version]) -> None:
@@ -429,31 +400,6 @@
             raise MultiplyDefinedSymbolError(
                 sorted(list(multiply_defined_symbols)))
 
-    def check_llndk_introduced(self, versions: Iterable[Version]) -> None:
-        """Raises errors when llndk= is missing for new llndk symbols."""
-        if not self.filter.llndk:
-            return
-
-        def assert_llndk_with_version(tags: Tags,  name: str) -> None:
-            has_llndk_introduced = False
-            for tag in tags:
-                if tag.startswith('llndk='):
-                    has_llndk_introduced = True
-                    break
-            if not has_llndk_introduced:
-                raise ParseError(f'{name}: missing version. `llndk=yyyymm`')
-
-        arch = self.filter.arch
-        for version in versions:
-            # llndk symbols >= introduced=35 should be tagged
-            # explicitly with llndk=yyyymm.
-            for symbol in version.symbols:
-                if not symbol.tags.has_llndk_tags:
-                    continue
-                if symbol_in_api(symbol.tags, arch, 34):
-                    continue
-                assert_llndk_with_version(symbol.tags, symbol.name)
-
     def parse_version(self) -> Version:
         """Parses a single version section and returns a Version object."""
         assert self.current_line is not None
@@ -487,9 +433,7 @@
                 else:
                     raise ParseError('Unknown visiblity label: ' + visibility)
             elif global_scope and not cpp_symbols:
-                symbol = self.parse_symbol()
-                symbol.tags.copy_introduced_from(tags)
-                symbols.append(symbol)
+                symbols.append(self.parse_symbol())
             else:
                 # We're in a hidden scope or in 'extern "C++"' block. Ignore
                 # everything.
diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py
index 8b412b9..14bb737 100644
--- a/cc/symbolfile/test_symbolfile.py
+++ b/cc/symbolfile/test_symbolfile.py
@@ -344,45 +344,6 @@
         self.assertInclude(f_llndk, s_none)
         self.assertInclude(f_llndk, s_llndk)
 
-    def test_omit_llndk_versioned(self) -> None:
-        f_ndk = self.filter
-        f_ndk.api = 35
-
-        f_llndk = copy(f_ndk)
-        f_llndk.llndk = True
-        f_llndk.api = 202404
-
-        s = Symbol('foo', Tags())
-        s_llndk = Symbol('foo', Tags.from_strs(['llndk']))
-        s_llndk_202404 = Symbol('foo', Tags.from_strs(['llndk=202404']))
-        s_34 = Symbol('foo', Tags.from_strs(['introduced=34']))
-        s_34_llndk = Symbol('foo', Tags.from_strs(['introduced=34', 'llndk']))
-        s_35 = Symbol('foo', Tags.from_strs(['introduced=35']))
-        s_35_llndk_202404 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202404']))
-        s_35_llndk_202504 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202504']))
-
-        # When targeting NDK, omit LLNDK tags
-        self.assertInclude(f_ndk, s)
-        self.assertOmit(f_ndk, s_llndk)
-        self.assertOmit(f_ndk, s_llndk_202404)
-        self.assertInclude(f_ndk, s_34)
-        self.assertOmit(f_ndk, s_34_llndk)
-        self.assertInclude(f_ndk, s_35)
-        self.assertOmit(f_ndk, s_35_llndk_202404)
-        self.assertOmit(f_ndk, s_35_llndk_202504)
-
-        # When targeting LLNDK, old symbols without any mode tags are included as LLNDK
-        self.assertInclude(f_llndk, s)
-        # When targeting LLNDK, old symbols with #llndk are included as LLNDK
-        self.assertInclude(f_llndk, s_llndk)
-        self.assertInclude(f_llndk, s_llndk_202404)
-        self.assertInclude(f_llndk, s_34)
-        self.assertInclude(f_llndk, s_34_llndk)
-        # When targeting LLNDK, new symbols(>=35) should be tagged with llndk-introduced=.
-        self.assertOmit(f_llndk, s_35)
-        self.assertInclude(f_llndk, s_35_llndk_202404)
-        self.assertOmit(f_llndk, s_35_llndk_202504)
-
     def test_omit_apex(self) -> None:
         f_none = self.filter
         f_apex = copy(f_none)
@@ -494,8 +455,8 @@
         # should_omit_tags() can differently based on introduced API level when treating
         # LLNDK-available symbols.
         expected_symbols = [
-            Symbol('baz', Tags.from_strs(['introduced=35'])),
-            Symbol('qux', Tags.from_strs(['apex', 'llndk', 'introduced=35'])),
+            Symbol('baz', Tags()),
+            Symbol('qux', Tags.from_strs(['apex', 'llndk'])),
         ]
         self.assertEqual(expected_symbols, version.symbols)
 
@@ -643,19 +604,6 @@
         ]
         self.assertEqual(expected_symbols, version.symbols)
 
-    def test_parse_llndk_version_is_missing(self) -> None:
-        input_file = io.StringIO(textwrap.dedent("""\
-            VERSION_1 { # introduced=35
-                foo;
-                bar; # llndk
-            };
-        """))
-        f = copy(self.filter)
-        f.llndk = True
-        parser = symbolfile.SymbolFileParser(input_file, {}, f)
-        with self.assertRaises(symbolfile.ParseError):
-            parser.parse()
-
 
 def main() -> None:
     suite = unittest.TestLoader().loadTestsFromName(__name__)
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 90409b3..c8e27e5 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -80,6 +80,12 @@
 	// When set to true, sign the image with avbtool. Default is false.
 	Use_avb *bool
 
+	// This can either be "default", or "make_legacy". "make_legacy" will sign the boot image
+	// like how build/make/core/Makefile does, to get bit-for-bit backwards compatibility. But
+	// we may want to reconsider if it's necessary to have two modes in the future. The default
+	// is "default"
+	Avb_mode *string
+
 	// Name of the partition stored in vbmeta desc. Defaults to the name of this module.
 	Partition_name *string
 
@@ -90,6 +96,9 @@
 	// Hash and signing algorithm for avbtool. Default is SHA256_RSA4096.
 	Avb_algorithm *string
 
+	// The index used to prevent rollback of the image on device.
+	Avb_rollback_index *int64
+
 	// The security patch passed to as the com.android.build.<type>.security_patch avb property.
 	// Replacement for the make variables BOOT_SECURITY_PATCH / INIT_BOOT_SECURITY_PATCH.
 	Security_patch *string
@@ -197,16 +206,16 @@
 
 	output := unsignedOutput
 	if proptools.Bool(b.properties.Use_avb) {
-		// This bootimg module supports 2 modes of avb signing, it picks between them based on
-		// if the private key is specified or not. If there is a key, it does a signing process
-		// similar to how the regular partitions (system, product, vendor, etc) are signed.
-		// If the key is not provided, it will just add an avb footer to the image. The avb
-		// footer only signing is how the make-built init_boot, boot, and vendor_boot images are
-		// built.
-		if proptools.String(b.properties.Avb_private_key) != "" {
+		// This bootimg module supports 2 modes of avb signing. It is not clear to this author
+		// why there are differences, but one of them is to match the behavior of make-built boot
+		// images.
+		switch proptools.StringDefault(b.properties.Avb_mode, "default") {
+		case "default":
 			output = b.signImage(ctx, unsignedOutput)
-		} else {
+		case "make_legacy":
 			output = b.addAvbFooter(ctx, unsignedOutput, kernel)
+		default:
+			ctx.PropertyErrorf("avb_mode", `Unknown value for avb_mode, expected "default" or "make_legacy", got: %q`, *b.properties.Avb_mode)
 		}
 	}
 
@@ -328,13 +337,22 @@
 
 	cmd.FlagWithArg("--partition_name ", b.bootImageType.String())
 
+	if b.properties.Avb_algorithm != nil {
+		cmd.FlagWithArg("--algorithm ", proptools.NinjaAndShellEscape(*b.properties.Avb_algorithm))
+	}
+
+	if b.properties.Avb_private_key != nil {
+		key := android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key))
+		cmd.FlagWithInput("--key ", key)
+	}
+
 	if !b.bootImageType.isVendorBoot() {
 		cmd.FlagWithArg("--prop ", proptools.NinjaAndShellEscape(fmt.Sprintf(
 			"com.android.build.%s.os_version:%s", b.bootImageType.String(), ctx.Config().PlatformVersionLastStable())))
 	}
 
 	fingerprintFile := ctx.Config().BuildFingerprintFile(ctx)
-	cmd.FlagWithArg("--prop ", fmt.Sprintf("com.android.build.%s.fingerprint:%s", b.bootImageType.String(), fingerprintFile.String()))
+	cmd.FlagWithArg("--prop ", fmt.Sprintf("com.android.build.%s.fingerprint:$(cat %s)", b.bootImageType.String(), fingerprintFile.String()))
 	cmd.OrderOnly(fingerprintFile)
 
 	if b.properties.Security_patch != nil {
@@ -342,6 +360,10 @@
 			"com.android.build.%s.security_patch:%s", b.bootImageType.String(), *b.properties.Security_patch)))
 	}
 
+	if b.properties.Avb_rollback_index != nil {
+		cmd.FlagWithArg("--rollback_index ", strconv.FormatInt(*b.properties.Avb_rollback_index, 10))
+	}
+
 	builder.Build("add_avb_footer", fmt.Sprintf("Adding avb footer to %s", b.BaseModuleName()))
 	return output
 }
diff --git a/fsgen/boot_imgs.go b/fsgen/boot_imgs.go
index b651862..799dbc9 100644
--- a/fsgen/boot_imgs.go
+++ b/fsgen/boot_imgs.go
@@ -6,11 +6,12 @@
 	"fmt"
 	"path/filepath"
 	"strconv"
+	"strings"
 
 	"github.com/google/blueprint/proptools"
 )
 
-func createBootImage(ctx android.LoadHookContext) bool {
+func createBootImage(ctx android.LoadHookContext, dtbImg dtbImg) bool {
 	partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
 
 	if partitionVariables.TargetKernelPath == "" {
@@ -38,7 +39,8 @@
 
 	var partitionSize *int64
 	if partitionVariables.BoardBootimagePartitionSize != "" {
-		parsed, err := strconv.ParseInt(partitionVariables.BoardBootimagePartitionSize, 10, 64)
+		// Base of zero will allow base 10 or base 16 if starting with 0x
+		parsed, err := strconv.ParseInt(partitionVariables.BoardBootimagePartitionSize, 0, 64)
 		if err != nil {
 			panic(fmt.Sprintf("BOARD_BOOTIMAGE_PARTITION_SIZE must be an int, got %s", partitionVariables.BoardBootimagePartitionSize))
 		}
@@ -50,16 +52,34 @@
 		securityPatch = &partitionVariables.BootSecurityPatch
 	}
 
+	avbInfo := getAvbInfo(ctx.Config(), "boot")
+
 	bootImageName := generatedModuleNameForPartition(ctx.Config(), "boot")
 
+	var dtbPrebuilt *string
+	if dtbImg.include && dtbImg.imgType == "boot" {
+		dtbPrebuilt = proptools.StringPtr(":" + dtbImg.name)
+	}
+
+	var cmdline []string
+	if !buildingVendorBootImage(partitionVariables) {
+		cmdline = partitionVariables.InternalKernelCmdline
+	}
+
 	ctx.CreateModule(
 		filesystem.BootimgFactory,
 		&filesystem.BootimgProperties{
-			Kernel_prebuilt: proptools.StringPtr(":" + kernelFilegroupName),
-			Header_version:  proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
-			Partition_size:  partitionSize,
-			Use_avb:         &partitionVariables.BoardAvbEnable,
-			Security_patch:  securityPatch,
+			Kernel_prebuilt:    proptools.StringPtr(":" + kernelFilegroupName),
+			Header_version:     proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
+			Partition_size:     partitionSize,
+			Use_avb:            avbInfo.avbEnable,
+			Avb_mode:           avbInfo.avbMode,
+			Avb_private_key:    avbInfo.avbkeyFilegroup,
+			Avb_rollback_index: avbInfo.avbRollbackIndex,
+			Avb_algorithm:      avbInfo.avbAlgorithm,
+			Security_patch:     securityPatch,
+			Dtb_prebuilt:       dtbPrebuilt,
+			Cmdline:            cmdline,
 		},
 		&struct {
 			Name *string
@@ -70,18 +90,33 @@
 	return true
 }
 
-func createVendorBootImage(ctx android.LoadHookContext) bool {
+func createVendorBootImage(ctx android.LoadHookContext, dtbImg dtbImg) bool {
 	partitionVariables := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
 
 	bootImageName := generatedModuleNameForPartition(ctx.Config(), "vendor_boot")
 
+	avbInfo := getAvbInfo(ctx.Config(), "vendor_boot")
+
+	var dtbPrebuilt *string
+	if dtbImg.include && dtbImg.imgType == "vendor_boot" {
+		dtbPrebuilt = proptools.StringPtr(":" + dtbImg.name)
+	}
+
+	cmdline := partitionVariables.InternalKernelCmdline
+
 	ctx.CreateModule(
 		filesystem.BootimgFactory,
 		&filesystem.BootimgProperties{
-			Boot_image_type: proptools.StringPtr("vendor_boot"),
-			Ramdisk_module:  proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_ramdisk")),
-			Header_version:  proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
-			Use_avb:         &partitionVariables.BoardAvbEnable,
+			Boot_image_type:    proptools.StringPtr("vendor_boot"),
+			Ramdisk_module:     proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_ramdisk")),
+			Header_version:     proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
+			Use_avb:            avbInfo.avbEnable,
+			Avb_mode:           avbInfo.avbMode,
+			Avb_private_key:    avbInfo.avbkeyFilegroup,
+			Avb_rollback_index: avbInfo.avbRollbackIndex,
+			Avb_algorithm:      avbInfo.avbAlgorithm,
+			Dtb_prebuilt:       dtbPrebuilt,
+			Cmdline:            cmdline,
 		},
 		&struct {
 			Name *string
@@ -104,14 +139,31 @@
 		securityPatch = &partitionVariables.BootSecurityPatch
 	}
 
+	var partitionSize *int64
+	if partitionVariables.BoardInitBootimagePartitionSize != "" {
+		// Base of zero will allow base 10 or base 16 if starting with 0x
+		parsed, err := strconv.ParseInt(partitionVariables.BoardInitBootimagePartitionSize, 0, 64)
+		if err != nil {
+			panic(fmt.Sprintf("BOARD_INIT_BOOT_IMAGE_PARTITION_SIZE must be an int, got %s", partitionVariables.BoardInitBootimagePartitionSize))
+		}
+		partitionSize = &parsed
+	}
+
+	avbInfo := getAvbInfo(ctx.Config(), "init_boot")
+
 	ctx.CreateModule(
 		filesystem.BootimgFactory,
 		&filesystem.BootimgProperties{
-			Boot_image_type: proptools.StringPtr("init_boot"),
-			Ramdisk_module:  proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "ramdisk")),
-			Header_version:  proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
-			Use_avb:         &partitionVariables.BoardAvbEnable,
-			Security_patch:  securityPatch,
+			Boot_image_type:    proptools.StringPtr("init_boot"),
+			Ramdisk_module:     proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "ramdisk")),
+			Header_version:     proptools.StringPtr(partitionVariables.BoardBootHeaderVersion),
+			Security_patch:     securityPatch,
+			Partition_size:     partitionSize,
+			Use_avb:            avbInfo.avbEnable,
+			Avb_mode:           avbInfo.avbMode,
+			Avb_private_key:    avbInfo.avbkeyFilegroup,
+			Avb_rollback_index: avbInfo.avbRollbackIndex,
+			Avb_algorithm:      avbInfo.avbAlgorithm,
 		},
 		&struct {
 			Name *string
@@ -187,3 +239,47 @@
 	}
 	return int(v), true
 }
+
+type dtbImg struct {
+	// whether to include the dtb image in boot image
+	include bool
+
+	// name of the generated dtb image filegroup name
+	name string
+
+	// type of the boot image that the dtb image argument should be specified
+	imgType string
+}
+
+func createDtbImgFilegroup(ctx android.LoadHookContext) dtbImg {
+	partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+	if !partitionVars.BoardIncludeDtbInBootimg {
+		return dtbImg{include: false}
+	}
+	for _, copyFilePair := range partitionVars.ProductCopyFiles {
+		srcDestList := strings.Split(copyFilePair, ":")
+		if len(srcDestList) < 2 {
+			ctx.ModuleErrorf("PRODUCT_COPY_FILES must follow the format \"src:dest\", got: %s", copyFilePair)
+		}
+		if srcDestList[1] == "dtb.img" {
+			moduleName := generatedModuleName(ctx.Config(), "dtb_img_filegroup")
+			ctx.CreateModuleInDirectory(
+				android.FileGroupFactory,
+				filepath.Dir(srcDestList[0]),
+				&struct {
+					Name *string
+					Srcs []string
+				}{
+					Name: proptools.StringPtr(moduleName),
+					Srcs: []string{filepath.Base(srcDestList[1])},
+				},
+			)
+			imgType := "vendor_boot"
+			if !buildingVendorBootImage(partitionVars) {
+				imgType = "boot"
+			}
+			return dtbImg{include: true, name: moduleName, imgType: imgType}
+		}
+	}
+	return dtbImg{include: false}
+}
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index 6bfb097..e8b0a4f 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -124,15 +124,17 @@
 	}
 
 	partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+	dtbImg := createDtbImgFilegroup(ctx)
+
 	if buildingBootImage(partitionVars) {
-		if createBootImage(ctx) {
+		if createBootImage(ctx, dtbImg) {
 			f.properties.Boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "boot")
 		} else {
 			f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "boot")
 		}
 	}
 	if buildingVendorBootImage(partitionVars) {
-		if createVendorBootImage(ctx) {
+		if createVendorBootImage(ctx, dtbImg) {
 			f.properties.Vendor_boot_image = ":" + generatedModuleNameForPartition(ctx.Config(), "vendor_boot")
 		} else {
 			f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, "vendor_boot")
@@ -312,9 +314,11 @@
 		return false
 	}
 
-	if partitionType == "vendor" || partitionType == "product" {
+	if partitionType == "vendor" || partitionType == "product" || partitionType == "system" {
 		fsProps.Linker_config.Gen_linker_config = proptools.BoolPtr(true)
-		fsProps.Linker_config.Linker_config_srcs = f.createLinkerConfigSourceFilegroups(ctx, partitionType)
+		if partitionType != "system" {
+			fsProps.Linker_config.Linker_config_srcs = f.createLinkerConfigSourceFilegroups(ctx, partitionType)
+		}
 	}
 
 	if android.InList(partitionType, dlkmPartitions) {
@@ -546,42 +550,21 @@
 }
 
 func generateFsProps(ctx android.EarlyModuleContext, partitionType string) (*filesystem.FilesystemProperties, bool) {
-	fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
 	fsProps := &filesystem.FilesystemProperties{}
 
 	partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
-	var boardAvbEnable bool
-	var boardAvbKeyPath string
-	var boardAvbAlgorithm string
-	var boardAvbRollbackIndex string
+	var avbInfo avbInfo
 	var fsType string
 	if strings.Contains(partitionType, "ramdisk") {
 		fsType = "compressed_cpio"
 	} else {
 		specificPartitionVars := partitionVars.PartitionQualifiedVariables[partitionType]
 		fsType = specificPartitionVars.BoardFileSystemType
-		boardAvbEnable = partitionVars.BoardAvbEnable
-		boardAvbKeyPath = specificPartitionVars.BoardAvbKeyPath
-		boardAvbAlgorithm = specificPartitionVars.BoardAvbAlgorithm
-		boardAvbRollbackIndex = specificPartitionVars.BoardAvbRollbackIndex
-		if boardAvbEnable {
-			if boardAvbKeyPath == "" {
-				boardAvbKeyPath = partitionVars.BoardAvbKeyPath
-			}
-			if boardAvbAlgorithm == "" {
-				boardAvbAlgorithm = partitionVars.BoardAvbAlgorithm
-			}
-			if boardAvbRollbackIndex == "" {
-				boardAvbRollbackIndex = partitionVars.BoardAvbRollbackIndex
-			}
-		}
+		avbInfo = getAvbInfo(ctx.Config(), partitionType)
 		if fsType == "" {
 			fsType = "ext4" //default
 		}
 	}
-	if boardAvbKeyPath != "" {
-		boardAvbKeyPath = ":" + fsGenState.avbKeyFilegroups[boardAvbKeyPath]
-	}
 
 	fsProps.Type = proptools.StringPtr(fsType)
 	if filesystem.GetFsTypeFromString(ctx, *fsProps.Type).IsUnknown() {
@@ -594,15 +577,13 @@
 	fsProps.Unchecked_module = proptools.BoolPtr(true)
 
 	// BOARD_AVB_ENABLE
-	fsProps.Use_avb = proptools.BoolPtr(boardAvbEnable)
+	fsProps.Use_avb = avbInfo.avbEnable
 	// BOARD_AVB_KEY_PATH
-	fsProps.Avb_private_key = proptools.StringPtr(boardAvbKeyPath)
+	fsProps.Avb_private_key = avbInfo.avbkeyFilegroup
 	// BOARD_AVB_ALGORITHM
-	fsProps.Avb_algorithm = proptools.StringPtr(boardAvbAlgorithm)
+	fsProps.Avb_algorithm = avbInfo.avbAlgorithm
 	// BOARD_AVB_SYSTEM_ROLLBACK_INDEX
-	if rollbackIndex, err := strconv.ParseInt(boardAvbRollbackIndex, 10, 64); err == nil {
-		fsProps.Rollback_index = proptools.Int64Ptr(rollbackIndex)
-	}
+	fsProps.Rollback_index = avbInfo.avbRollbackIndex
 
 	fsProps.Partition_name = proptools.StringPtr(partitionType)
 
@@ -629,6 +610,55 @@
 	return fsProps, true
 }
 
+type avbInfo struct {
+	avbEnable        *bool
+	avbKeyPath       *string
+	avbkeyFilegroup  *string
+	avbAlgorithm     *string
+	avbRollbackIndex *int64
+	avbMode          *string
+}
+
+func getAvbInfo(config android.Config, partitionType string) avbInfo {
+	partitionVars := config.ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+	specificPartitionVars := partitionVars.PartitionQualifiedVariables[partitionType]
+	var result avbInfo
+	boardAvbEnable := partitionVars.BoardAvbEnable
+	if boardAvbEnable {
+		result.avbEnable = proptools.BoolPtr(true)
+		if specificPartitionVars.BoardAvbKeyPath != "" {
+			result.avbKeyPath = proptools.StringPtr(specificPartitionVars.BoardAvbKeyPath)
+		} else if partitionVars.BoardAvbKeyPath != "" {
+			result.avbKeyPath = proptools.StringPtr(partitionVars.BoardAvbKeyPath)
+		}
+		if specificPartitionVars.BoardAvbAlgorithm != "" {
+			result.avbAlgorithm = proptools.StringPtr(specificPartitionVars.BoardAvbAlgorithm)
+		} else if partitionVars.BoardAvbAlgorithm != "" {
+			result.avbAlgorithm = proptools.StringPtr(partitionVars.BoardAvbAlgorithm)
+		}
+		if specificPartitionVars.BoardAvbRollbackIndex != "" {
+			parsed, err := strconv.ParseInt(specificPartitionVars.BoardAvbRollbackIndex, 10, 64)
+			if err != nil {
+				panic(fmt.Sprintf("Rollback index must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndex))
+			}
+			result.avbRollbackIndex = &parsed
+		} else if partitionVars.BoardAvbRollbackIndex != "" {
+			parsed, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 64)
+			if err != nil {
+				panic(fmt.Sprintf("Rollback index must be an int, got %s", partitionVars.BoardAvbRollbackIndex))
+			}
+			result.avbRollbackIndex = &parsed
+		}
+		result.avbMode = proptools.StringPtr("make_legacy")
+	}
+	if result.avbKeyPath != nil {
+		fsGenState := config.Get(fsGenStateOnceKey).(*FsGenState)
+		filegroup := fsGenState.avbKeyFilegroups[*result.avbKeyPath]
+		result.avbkeyFilegroup = proptools.StringPtr(":" + filegroup)
+	}
+	return result
+}
+
 func (f *filesystemCreator) createFileListDiffTest(ctx android.ModuleContext, partitionType string) android.Path {
 	partitionModuleName := generatedModuleNameForPartition(ctx.Config(), partitionType)
 	systemImage := ctx.GetDirectDepWithTag(partitionModuleName, generatedFilesystemDepTag)
diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go
index 12f9956..9472a50 100644
--- a/fsgen/fsgen_mutators.go
+++ b/fsgen/fsgen_mutators.go
@@ -98,7 +98,6 @@
 					"com.android.apex.cts.shim.v1_prebuilt":     defaultDepCandidateProps(ctx.Config()),
 					"dex_bootjars":                              defaultDepCandidateProps(ctx.Config()),
 					"framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()),
-					"init.environ.rc-soong":                     defaultDepCandidateProps(ctx.Config()),
 					"libcompiler_rt":                            defaultDepCandidateProps(ctx.Config()),
 					"libdmabufheap":                             defaultDepCandidateProps(ctx.Config()),
 					"libgsi":                                    defaultDepCandidateProps(ctx.Config()),
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index fdccd3a..88a8fb8 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -105,6 +105,10 @@
 	set := map[string]struct{}{}
 	for _, name := range contents {
 		dep := ctx.GetDirectDepWithTag(name, tag)
+		if dep == nil && ctx.Config().AllowMissingDependencies() {
+			// Ignore apex boot jars from dexpreopt if it does not exist, and missing deps are allowed.
+			continue
+		}
 		set[ModuleStemForDeapexing(dep)] = struct{}{}
 		if m, ok := dep.(ModuleWithStem); ok {
 			set[m.Stem()] = struct{}{}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index bc26527..e955949 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -769,15 +769,6 @@
 // property is defined, apply transformations and only revert the flagged apis that are not
 // enabled via release configurations and are not specified in aconfig_declarations
 func generateRevertAnnotationArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsType StubsType, aconfigFlagsPaths android.Paths) {
-
-	if len(aconfigFlagsPaths) == 0 {
-		cmd.Flag("--revert-annotation android.annotation.FlaggedApi")
-		return
-	}
-
-	releasedFlaggedApisFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flagged-apis-%s.txt", stubsType.String()))
-	revertAnnotationsFile := android.PathForModuleOut(ctx, fmt.Sprintf("revert-annotations-%s.txt", stubsType.String()))
-
 	var filterArgs string
 	switch stubsType {
 	// No flagged apis specific flags need to be passed to metalava when generating
@@ -799,6 +790,15 @@
 		}
 	}
 
+	if len(aconfigFlagsPaths) == 0 {
+		// This argument should not be added for "everything" stubs
+		cmd.Flag("--revert-annotation android.annotation.FlaggedApi")
+		return
+	}
+
+	releasedFlaggedApisFile := android.PathForModuleOut(ctx, fmt.Sprintf("released-flagged-apis-%s.txt", stubsType.String()))
+	revertAnnotationsFile := android.PathForModuleOut(ctx, fmt.Sprintf("revert-annotations-%s.txt", stubsType.String()))
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        gatherReleasedFlaggedApisRule,
 		Inputs:      aconfigFlagsPaths,
diff --git a/java/java.go b/java/java.go
index 64ef782..260d336 100644
--- a/java/java.go
+++ b/java/java.go
@@ -2311,14 +2311,17 @@
 		case libTag:
 			if provider, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
 				classPaths = append(classPaths, provider.HeaderJars...)
+				al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.AconfigIntermediateCacheOutputPaths...)
 			}
 		case bootClasspathTag:
 			if provider, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
 				bootclassPaths = append(bootclassPaths, provider.HeaderJars...)
+				al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.AconfigIntermediateCacheOutputPaths...)
 			}
 		case staticLibTag:
 			if provider, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok {
 				staticLibs = append(staticLibs, provider.HeaderJars...)
+				al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.AconfigIntermediateCacheOutputPaths...)
 			}
 		case systemModulesTag:
 			if sm, ok := android.OtherModuleProvider(ctx, dep, SystemModulesProvider); ok {
diff --git a/java/testing.go b/java/testing.go
index cb3245b..0ea4e64 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -428,7 +428,7 @@
 		"stub-annotations",
 
 		"aconfig-annotations-lib",
-		"aconfig_storage_reader_java",
+		"aconfig_storage_stub",
 		"unsupportedappusage",
 	}
 
diff --git a/rust/bindgen.go b/rust/bindgen.go
index d590579..898e792 100644
--- a/rust/bindgen.go
+++ b/rust/bindgen.go
@@ -300,6 +300,11 @@
 	// it cannot recognize. Turn off unknown warning flags warning.
 	cflags = append(cflags, "-Wno-unknown-warning-option")
 
+	// Suppress warnings while testing a new compiler.
+	if ctx.Config().IsEnvTrue("LLVM_NEXT") {
+		cflags = append(cflags, "-Wno-everything")
+	}
+
 	outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs")
 
 	var cmd, cmdDesc string
diff --git a/ui/status/log.go b/ui/status/log.go
index 14df346..7bfd396 100644
--- a/ui/status/log.go
+++ b/ui/status/log.go
@@ -22,6 +22,8 @@
 	"io/ioutil"
 	"os"
 	"strings"
+	"sync"
+	"time"
 
 	"google.golang.org/protobuf/proto"
 
@@ -31,7 +33,10 @@
 )
 
 type verboseLog struct {
-	w io.WriteCloser
+	w    *gzip.Writer
+	lock *sync.Mutex
+	data chan []string
+	stop chan bool
 }
 
 func NewVerboseLog(log logger.Logger, filename string) StatusOutput {
@@ -47,9 +52,42 @@
 
 	w := gzip.NewWriter(f)
 
-	return &verboseLog{
-		w: w,
+	l := &verboseLog{
+		w:    w,
+		lock: &sync.Mutex{},
+		data: make(chan []string),
+		stop: make(chan bool),
 	}
+	l.startWriter()
+	return l
+}
+
+func (v *verboseLog) startWriter() {
+	go func() {
+		tick := time.Tick(time.Second)
+		for {
+			select {
+			case <-v.stop:
+				close(v.data)
+				v.w.Close()
+				return
+			case <-tick:
+				v.w.Flush()
+			case dataList := <-v.data:
+				for _, data := range dataList {
+					fmt.Fprint(v.w, data)
+				}
+			}
+		}
+	}()
+}
+
+func (v *verboseLog) stopWriter() {
+	v.stop <- true
+}
+
+func (v *verboseLog) queueWrite(s ...string) {
+	v.data <- s
 }
 
 func (v *verboseLog) StartAction(action *Action, counts Counts) {}
@@ -60,27 +98,27 @@
 		cmd = result.Description
 	}
 
-	fmt.Fprintf(v.w, "[%d/%d] %s\n", counts.FinishedActions, counts.TotalActions, cmd)
+	v.queueWrite(fmt.Sprintf("[%d/%d] ", counts.FinishedActions, counts.TotalActions), cmd, "\n")
 
 	if result.Error != nil {
-		fmt.Fprintf(v.w, "FAILED: %s\n", strings.Join(result.Outputs, " "))
+		v.queueWrite("FAILED: ", strings.Join(result.Outputs, " "), "\n")
 	}
 
 	if result.Output != "" {
-		fmt.Fprintln(v.w, result.Output)
+		v.queueWrite(result.Output, "\n")
 	}
 }
 
 func (v *verboseLog) Flush() {
-	v.w.Close()
+	v.stopWriter()
 }
 
 func (v *verboseLog) Message(level MsgLevel, message string) {
-	fmt.Fprintf(v.w, "%s%s\n", level.Prefix(), message)
+	v.queueWrite(level.Prefix(), message, "\n")
 }
 
 func (v *verboseLog) Write(p []byte) (int, error) {
-	fmt.Fprint(v.w, string(p))
+	v.queueWrite(string(p))
 	return len(p), nil
 }