Merge "Change depVisitor to use providers instead of type-asserting to interfaces directly, the next step is to change it to use ModuleProxy once IsDepInSameApex is ready." into main
diff --git a/android/androidmk.go b/android/androidmk.go
index 7d6b056..62ab596 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -779,17 +779,6 @@
 func (so *soongOnlyAndroidMkSingleton) soongOnlyBuildActions(ctx SingletonContext, mods []blueprint.Module) {
 	allDistContributions, moduleInfoJSONs := getSoongOnlyDataFromMods(ctx, mods)
 
-	for _, provider := range append(makeVarsInitProviders, *getSingletonMakevarsProviders(ctx.Config())...) {
-		mctx := &makeVarsContext{
-			SingletonContext: ctx,
-			pctx:             provider.pctx,
-		}
-		provider.call(mctx)
-		if contribution := distsToDistContributions(mctx.dists); contribution != nil {
-			allDistContributions = append(allDistContributions, *contribution)
-		}
-	}
-
 	singletonDists := getSingletonDists(ctx.Config())
 	singletonDists.lock.Lock()
 	if contribution := distsToDistContributions(singletonDists.dists); contribution != nil {
@@ -966,31 +955,6 @@
 					}
 				}
 			}
-			if x, ok := mod.(ModuleMakeVarsProvider); ok {
-				mctx := &makeVarsContext{
-					SingletonContext: ctx.(SingletonContext),
-					config:           ctx.Config(),
-					pctx:             pctx,
-				}
-				if !x.Enabled(ctx) {
-					continue
-				}
-				x.MakeVars(mctx)
-				if contribution := distsToDistContributions(mctx.dists); contribution != nil {
-					allDistContributions = append(allDistContributions, *contribution)
-				}
-			}
-			if x, ok := mod.(SingletonMakeVarsProvider); ok {
-				mctx := &makeVarsContext{
-					SingletonContext: ctx.(SingletonContext),
-					config:           ctx.Config(),
-					pctx:             pctx,
-				}
-				x.MakeVars(mctx)
-				if contribution := distsToDistContributions(mctx.dists); contribution != nil {
-					allDistContributions = append(allDistContributions, *contribution)
-				}
-			}
 		}
 	}
 	return allDistContributions, moduleInfoJSONs
diff --git a/android/config.go b/android/config.go
index acaad60..3867c11 100644
--- a/android/config.go
+++ b/android/config.go
@@ -394,6 +394,17 @@
 	// Add others as needed.
 }
 
+// These are the flags when `SOONG_PARTIAL_COMPILE` is empty or not set.
+var defaultPartialCompileFlags = partialCompileFlags{
+	Enabled: false,
+}
+
+// These are the flags when `SOONG_PARTIAL_COMPILE=true`.
+var enabledPartialCompileFlags = partialCompileFlags{
+	Enabled: true,
+	Use_d8:  true,
+}
+
 type deviceConfig struct {
 	config *config
 	OncePer
@@ -427,11 +438,6 @@
 // To add a new feature to the list, add the field in the struct
 // `partialCompileFlags` above, and then add the name of the field in the
 // switch statement below.
-var defaultPartialCompileFlags = partialCompileFlags{
-	// Set any opt-out flags here.  Opt-in flags are off by default.
-	Enabled: false,
-}
-
 func (c *config) parsePartialCompileFlags(isEngBuild bool) (partialCompileFlags, error) {
 	if !isEngBuild {
 		return partialCompileFlags{}, nil
@@ -472,8 +478,7 @@
 		}
 		switch tok {
 		case "true":
-			ret = defaultPartialCompileFlags
-			ret.Enabled = true
+			ret = enabledPartialCompileFlags
 		case "false":
 			// Set everything to false.
 			ret = partialCompileFlags{}
diff --git a/android/config_test.go b/android/config_test.go
index 4bdf05f..3d86860 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -239,10 +239,10 @@
 	}{
 		{"", true, defaultPartialCompileFlags},
 		{"false", true, partialCompileFlags{}},
-		{"true", true, defaultPartialCompileFlags.updateEnabled(true)},
+		{"true", true, enabledPartialCompileFlags},
 		{"true", false, partialCompileFlags{}},
-		{"true,use_d8", true, defaultPartialCompileFlags.updateEnabled(true).updateUseD8(true)},
-		{"true,-use_d8", true, defaultPartialCompileFlags.updateEnabled(true).updateUseD8(false)},
+		{"true,use_d8", true, enabledPartialCompileFlags.updateUseD8(true)},
+		{"true,-use_d8", true, enabledPartialCompileFlags.updateUseD8(false)},
 		{"use_d8,false", true, partialCompileFlags{}},
 		{"false,+use_d8", true, partialCompileFlags{}.updateUseD8(true)},
 	}
diff --git a/android/makevars.go b/android/makevars.go
index baa1d44..2931d0b 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -65,24 +65,6 @@
 	// dependencies to be added to it.  Phony can be called on the same name multiple
 	// times to add additional dependencies.
 	Phony(names string, deps ...Path)
-
-	// DistForGoal creates a rule to copy one or more Paths to the artifacts
-	// directory on the build server when the specified goal is built.
-	DistForGoal(goal string, paths ...Path)
-
-	// DistForGoalWithFilename creates a rule to copy a Path to the artifacts
-	// directory on the build server with the given filename when the specified
-	// goal is built.
-	DistForGoalWithFilename(goal string, path Path, filename string)
-
-	// DistForGoals creates a rule to copy one or more Paths to the artifacts
-	// directory on the build server when any of the specified goals are built.
-	DistForGoals(goals []string, paths ...Path)
-
-	// DistForGoalsWithFilename creates a rule to copy a Path to the artifacts
-	// directory on the build server with the given filename when any of the
-	// specified goals are built.
-	DistForGoalsWithFilename(goals []string, path Path, filename string)
 }
 
 // MakeVarsContext contains the set of functions available for MakeVarsProvider
@@ -198,11 +180,9 @@
 
 type makeVarsContext struct {
 	SingletonContext
-	config  Config
 	pctx    PackageContext
 	vars    []makeVarsVariable
 	phonies []phony
-	dists   []dist
 }
 
 var _ MakeVarsContext = &makeVarsContext{}
@@ -263,7 +243,6 @@
 
 		vars = append(vars, mctx.vars...)
 		phonies = append(phonies, mctx.phonies...)
-		dists = append(dists, mctx.dists...)
 	}
 
 	singletonDists := getSingletonDists(ctx.Config())
@@ -281,7 +260,6 @@
 
 			vars = append(vars, mctx.vars...)
 			phonies = append(phonies, mctx.phonies...)
-			dists = append(dists, mctx.dists...)
 		}
 
 		if m.ExportedToMake() {
@@ -611,13 +589,6 @@
 	c.phonies = append(c.phonies, phony{name, deps})
 }
 
-func (c *makeVarsContext) addDist(goals []string, paths []distCopy) {
-	c.dists = append(c.dists, dist{
-		goals: goals,
-		paths: paths,
-	})
-}
-
 func (c *makeVarsContext) Strict(name, ninjaStr string) {
 	c.addVariable(name, ninjaStr, true, false)
 }
@@ -641,26 +612,3 @@
 func (c *makeVarsContext) Phony(name string, deps ...Path) {
 	c.addPhony(name, Paths(deps).Strings())
 }
-
-func (c *makeVarsContext) DistForGoal(goal string, paths ...Path) {
-	c.DistForGoals([]string{goal}, paths...)
-}
-
-func (c *makeVarsContext) DistForGoalWithFilename(goal string, path Path, filename string) {
-	c.DistForGoalsWithFilename([]string{goal}, path, filename)
-}
-
-func (c *makeVarsContext) DistForGoals(goals []string, paths ...Path) {
-	var copies distCopies
-	for _, path := range paths {
-		copies = append(copies, distCopy{
-			from: path,
-			dest: path.Base(),
-		})
-	}
-	c.addDist(goals, copies)
-}
-
-func (c *makeVarsContext) DistForGoalsWithFilename(goals []string, path Path, filename string) {
-	c.addDist(goals, distCopies{{from: path, dest: filename}})
-}
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 570f36c..6485cc5 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -103,25 +103,26 @@
 func init() {
 	addStandardProperties(bpparser.StringType,
 		map[string]string{
-			"LOCAL_MODULE":                  "name",
-			"LOCAL_CXX_STL":                 "stl",
-			"LOCAL_MULTILIB":                "compile_multilib",
-			"LOCAL_ARM_MODE_HACK":           "instruction_set",
-			"LOCAL_SDK_VERSION":             "sdk_version",
-			"LOCAL_MIN_SDK_VERSION":         "min_sdk_version",
-			"LOCAL_TARGET_SDK_VERSION":      "target_sdk_version",
-			"LOCAL_NDK_STL_VARIANT":         "stl",
-			"LOCAL_JAR_MANIFEST":            "manifest",
-			"LOCAL_CERTIFICATE":             "certificate",
-			"LOCAL_CERTIFICATE_LINEAGE":     "lineage",
-			"LOCAL_PACKAGE_NAME":            "name",
-			"LOCAL_MODULE_RELATIVE_PATH":    "relative_install_path",
-			"LOCAL_PROTOC_OPTIMIZE_TYPE":    "proto.type",
-			"LOCAL_MODULE_OWNER":            "owner",
-			"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
-			"LOCAL_JAVA_LANGUAGE_VERSION":   "java_version",
-			"LOCAL_INSTRUMENTATION_FOR":     "instrumentation_for",
-			"LOCAL_MANIFEST_FILE":           "manifest",
+			"LOCAL_MODULE":                   "name",
+			"LOCAL_CXX_STL":                  "stl",
+			"LOCAL_MULTILIB":                 "compile_multilib",
+			"LOCAL_ARM_MODE_HACK":            "instruction_set",
+			"LOCAL_SDK_VERSION":              "sdk_version",
+			"LOCAL_MIN_SDK_VERSION":          "min_sdk_version",
+			"LOCAL_ROTATION_MIN_SDK_VERSION": "rotationMinSdkVersion",
+			"LOCAL_TARGET_SDK_VERSION":       "target_sdk_version",
+			"LOCAL_NDK_STL_VARIANT":          "stl",
+			"LOCAL_JAR_MANIFEST":             "manifest",
+			"LOCAL_CERTIFICATE":              "certificate",
+			"LOCAL_CERTIFICATE_LINEAGE":      "lineage",
+			"LOCAL_PACKAGE_NAME":             "name",
+			"LOCAL_MODULE_RELATIVE_PATH":     "relative_install_path",
+			"LOCAL_PROTOC_OPTIMIZE_TYPE":     "proto.type",
+			"LOCAL_MODULE_OWNER":             "owner",
+			"LOCAL_RENDERSCRIPT_TARGET_API":  "renderscript.target_api",
+			"LOCAL_JAVA_LANGUAGE_VERSION":    "java_version",
+			"LOCAL_INSTRUMENTATION_FOR":      "instrumentation_for",
+			"LOCAL_MANIFEST_FILE":            "manifest",
 
 			"LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile",
 			"LOCAL_TEST_CONFIG":                      "test_config",
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 2c06924..7240ea5 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2689,7 +2689,7 @@
 	cppOnly := []string{"-fPIC", "${config.CommonGlobalCppflags}", "${config.DeviceGlobalCppflags}", "${config.ArmCppflags}"}
 
 	cflags := []string{"-Werror", "-std=candcpp"}
-	cstd := []string{"-std=gnu17", "-std=conly"}
+	cstd := []string{"-std=gnu23", "-std=conly"}
 	cppstd := []string{"-std=gnu++20", "-std=cpp", "-fno-rtti"}
 
 	lastNDKFlags := []string{
diff --git a/cc/config/global.go b/cc/config/global.go
index 7bea124..5011acd 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -375,7 +375,7 @@
 		"-w",
 	}
 
-	CStdVersion               = "gnu17"
+	CStdVersion               = "gnu23"
 	CppStdVersion             = "gnu++20"
 	ExperimentalCStdVersion   = "gnu2x"
 	ExperimentalCppStdVersion = "gnu++2b"
diff --git a/cc/test.go b/cc/test.go
index b3b2ae8..2c5c36e 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -418,6 +418,10 @@
 			if test.testConfig != nil {
 				ctx.InstallFile(testCases, ctx.ModuleName()+".config", test.testConfig)
 			}
+			dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml")
+			if dynamicConfig.Valid() {
+				ctx.InstallFile(testCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path())
+			}
 			for _, extraTestConfig := range test.extraTestConfigs {
 				ctx.InstallFile(testCases, extraTestConfig.Base(), extraTestConfig)
 			}
diff --git a/filesystem/android_device.go b/filesystem/android_device.go
index 8d7f92f..4f6f983 100644
--- a/filesystem/android_device.go
+++ b/filesystem/android_device.go
@@ -302,11 +302,6 @@
 		targetFilesZipCopy{a.partitionProps.Init_boot_partition_name, "INIT_BOOT/RAMDISK"},
 		targetFilesZipCopy{a.partitionProps.Vendor_boot_partition_name, "VENDOR_BOOT/RAMDISK"},
 	}
-	// TODO: Handle cases where recovery files are copied to BOOT/ or RECOVERY/
-	// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=6211-6219?q=core%2FMakefile&ss=android%2Fplatform%2Fsuperproject%2Fmain
-	if ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() {
-		toCopy = append(toCopy, targetFilesZipCopy{a.partitionProps.Recovery_partition_name, "VENDOR_BOOT/RAMDISK"})
-	}
 
 	filesystemsToCopy := []targetFilesystemZipCopy{}
 	for _, zipCopy := range toCopy {
@@ -343,6 +338,12 @@
 			BuiltTool("acp").
 			Textf("-rd %s/. %s/%s", rootDirString, targetFilesDir, toCopy.destSubdir).
 			Implicit(toCopy.fsInfo.Output) // so that the staging dir is built
+		for _, extraRootDir := range toCopy.fsInfo.ExtraRootDirs {
+			builder.Command().
+				BuiltTool("acp").
+				Textf("-rd %s/. %s/%s", extraRootDir, targetFilesDir, toCopy.destSubdir).
+				Implicit(toCopy.fsInfo.Output) // so that the staging dir is built
+		}
 
 		if toCopy.destSubdir == "SYSTEM" {
 			// Create the ROOT partition in target_files.zip
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 3829399..c0fb636 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -400,6 +400,9 @@
 	// to add a dependency on the Output file, as you cannot add dependencies on directories
 	// in ninja.
 	RootDir android.Path
+	// Extra root directories that are also built into the partition. Currently only used for
+	// including the recovery partition files into the vendor_boot image.
+	ExtraRootDirs android.Paths
 	// The rebased staging directory used to build the output filesystem. If consuming this, make
 	// sure to add a dependency on the Output file, as you cannot add dependencies on directories
 	// in ninja. In many cases this is the same as RootDir, only in the system partition is it
@@ -615,6 +618,7 @@
 	var outputHermetic android.WritablePath
 	var buildImagePropFile android.Path
 	var buildImagePropFileDeps android.Paths
+	var extraRootDirs android.Paths
 	switch f.fsType(ctx) {
 	case ext4Type, erofsType, f2fsType:
 		buildImagePropFile, buildImagePropFileDeps = f.buildPropFile(ctx)
@@ -628,9 +632,9 @@
 		f.buildImageUsingBuildImage(ctx, hermeticBuilder, buildImageParams{rootDir, propFileHermetic, buildImagePropFileDeps, outputHermetic})
 		mapFile = f.getMapFile(ctx)
 	case compressedCpioType:
-		f.output = f.buildCpioImage(ctx, builder, rootDir, true)
+		f.output, extraRootDirs = f.buildCpioImage(ctx, builder, rootDir, true)
 	case cpioType:
-		f.output = f.buildCpioImage(ctx, builder, rootDir, false)
+		f.output, extraRootDirs = f.buildCpioImage(ctx, builder, rootDir, false)
 	default:
 		return
 	}
@@ -663,6 +667,7 @@
 		OutputHermetic:         outputHermetic,
 		FileListFile:           fileListFile,
 		RootDir:                rootDir,
+		ExtraRootDirs:          extraRootDirs,
 		RebasedDir:             rebasedDir,
 		MapFile:                mapFile,
 		ModuleName:             ctx.ModuleName(),
@@ -1161,7 +1166,7 @@
 	builder *android.RuleBuilder,
 	rootDir android.OutputPath,
 	compressed bool,
-) android.Path {
+) (android.Path, android.Paths) {
 	if proptools.Bool(f.properties.Use_avb) {
 		ctx.PropertyErrorf("use_avb", "signing compresed cpio image using avbtool is not supported."+
 			"Consider adding this to bootimg module and signing the entire boot image.")
@@ -1201,7 +1206,7 @@
 	// rootDir is not deleted. Might be useful for quick inspection.
 	builder.Build("build_cpio_image", fmt.Sprintf("Creating filesystem %s", f.BaseModuleName()))
 
-	return output
+	return output, rootDirs
 }
 
 var validPartitions = []string{
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
index c2721d2..e2485a1 100644
--- a/fsgen/filesystem_creator.go
+++ b/fsgen/filesystem_creator.go
@@ -377,7 +377,7 @@
 	if modName := partitions.nameForType("userdata"); modName != "" {
 		partitionProps.Userdata_partition_name = proptools.StringPtr(modName)
 	}
-	if modName := partitions.nameForType("recovery"); modName != "" {
+	if modName := partitions.nameForType("recovery"); modName != "" && !ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() {
 		partitionProps.Recovery_partition_name = proptools.StringPtr(modName)
 	}
 	if modName := partitions.nameForType("system_dlkm"); modName != "" && !android.InList("system_dlkm", superImageSubPartitions) {
diff --git a/java/app.go b/java/app.go
index ccc60a4..9b10bf3 100644
--- a/java/app.go
+++ b/java/app.go
@@ -1643,6 +1643,10 @@
 		if a.testConfig != nil {
 			ctx.InstallFile(pathInTestCases, ctx.Module().Name()+".config", a.testConfig)
 		}
+		dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml")
+		if dynamicConfig.Valid() {
+			ctx.InstallFile(pathInTestCases, ctx.Module().Name()+".dynamic", dynamicConfig.Path())
+		}
 		testDeps := append(a.data, a.extraTestConfigs...)
 		for _, data := range android.SortedUniquePaths(testDeps) {
 			dataPath := android.DataPath{SrcPath: data}
diff --git a/java/dex.go b/java/dex.go
index 64465a2..c9d3f37 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -63,6 +63,14 @@
 		// Defaults to false for apps and tests, true for libraries.
 		Proguard_compatibility *bool
 
+		// If true, R8 will not add public or protected members (fields or methods) to
+		// the API surface of the compilation unit, i.e., classes that are kept or
+		// have kept subclasses will not expose any members added by R8 for internal
+		// use. That includes renamed members if obfuscation is enabled.
+		// This should only be used for building targets that go on the bootclasspath.
+		// Defaults to false.
+		Protect_api_surface *bool
+
 		// If true, optimize for size by removing unused code.  Defaults to true for apps,
 		// false for libraries and tests.
 		Shrink *bool
@@ -170,6 +178,71 @@
 		},
 	}, []string{"outDir", "d8Flags", "zipFlags", "mergeZipsFlags"}, nil)
 
+// Include all of the args for d8r8, so that we can generate the partialcompileclean target's build using the same list.
+var d8r8Clean = pctx.AndroidStaticRule("d8r8-partialcompileclean",
+	blueprint.RuleParams{
+		Command: `rm -rf "${outDir}" "${outDict}" "${outConfig}" "${outUsage}" "${outUsageZip}" "${outUsageDir}" ` +
+			`"${resourcesOutput}" "${outR8ArtProfile}" ${builtOut}`,
+	}, "outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", "builtOut",
+	"d8Flags", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile", "implicits",
+)
+
+var d8r8, d8r8RE = pctx.MultiCommandRemoteStaticRules("d8r8",
+	blueprint.RuleParams{
+		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
+			`rm -f "$outDict" && rm -f "$outConfig" && rm -rf "${outUsageDir}" && ` +
+			`mkdir -p $$(dirname ${outUsage}) && ` +
+			`if [ -n "$${SOONG_USE_PARTIAL_COMPILE}" ]; then ` +
+			` for f in "${outConfig}" "${outDict}" "${outUsage}" "${resourcesOutput}"; do ` +
+			`   test -n "$${f}" && test ! -f "$${f}" && mkdir -p "$$(dirname "$${f}")" && touch "$${f}" || true; ` +
+			` done && ` +
+			` $d8Template${config.D8Cmd} ${config.D8Flags} $d8Flags --output $outDir --no-dex-input-jar $in; ` +
+			`else ` +
+			` $r8Template${config.R8Cmd} ${config.R8Flags} $r8Flags -injars $in --output $outDir ` +
+			` --no-data-resources ` +
+			` -printmapping ${outDict} ` +
+			` -printconfiguration ${outConfig} ` +
+			` -printusage ${outUsage} ` +
+			` --deps-file ${out}.d && ` +
+			` touch "${outDict}" "${outConfig}" "${outUsage}"; ` +
+			`fi && ` +
+			`${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` +
+			`rm -rf ${outUsageDir} && ` +
+			`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
+			`${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` +
+			`rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar" `,
+		CommandDeps: []string{
+			"${config.D8Cmd}",
+			"${config.R8Cmd}",
+			"${config.SoongZipCmd}",
+			"${config.MergeZipsCmd}",
+		},
+	}, map[string]*remoteexec.REParams{
+		"$d8Template": &remoteexec.REParams{
+			Labels:          map[string]string{"type": "compile", "compiler": "d8"},
+			Inputs:          []string{"${config.D8Jar}"},
+			ExecStrategy:    "${config.RED8ExecStrategy}",
+			ToolchainInputs: []string{"${config.JavaCmd}"},
+			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		},
+		"$r8Template": &remoteexec.REParams{
+			Labels:          map[string]string{"type": "compile", "compiler": "r8"},
+			Inputs:          []string{"$implicits", "${config.R8Jar}"},
+			OutputFiles:     []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}", "${outR8ArtProfile}"},
+			ExecStrategy:    "${config.RER8ExecStrategy}",
+			ToolchainInputs: []string{"${config.JavaCmd}"},
+			Platform:        map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		},
+		"$zipTemplate": &remoteexec.REParams{
+			Labels:       map[string]string{"type": "tool", "name": "soong_zip"},
+			Inputs:       []string{"${config.SoongZipCmd}", "$outDir"},
+			OutputFiles:  []string{"$outDir/classes.dex.jar"},
+			ExecStrategy: "${config.RED8ExecStrategy}",
+			Platform:     map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+		},
+	}, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir",
+		"d8Flags", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile"}, []string{"implicits"})
+
 var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8",
 	blueprint.RuleParams{
 		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
@@ -390,6 +463,10 @@
 		r8Flags = append(r8Flags, "--force-proguard-compatibility")
 	}
 
+	if BoolDefault(opt.Protect_api_surface, false) {
+		r8Flags = append(r8Flags, "--protect-api-surface")
+	}
+
 	// Avoid unnecessary stack frame noise by only injecting source map ids for non-debug
 	// optimized or obfuscated targets.
 	if (Bool(opt.Optimize) || Bool(opt.Obfuscate)) && !debugMode {
@@ -482,6 +559,7 @@
 
 	// Compile classes.jar into classes.dex and then javalib.jar
 	javalibJar := android.PathForModuleOut(ctx, "dex", dexParams.jarName).OutputPath
+	cleanPhonyPath := android.PathForModuleOut(ctx, "dex", dexParams.jarName+"-partialcompileclean").OutputPath
 	outDir := android.PathForModuleOut(ctx, "dex")
 
 	zipFlags := "--ignore_missing_files"
@@ -498,7 +576,20 @@
 	}
 
 	useR8 := d.effectiveOptimizeEnabled()
+	useD8 := !useR8 || ctx.Config().PartialCompileFlags().Use_d8
+	rbeR8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8")
+	rbeD8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8")
+	var rule blueprint.Rule
+	var description string
 	var artProfileOutputPath *android.OutputPath
+	var implicitOutputs android.WritablePaths
+	var flags []string
+	var deps android.Paths
+	args := map[string]string{
+		"zipFlags":       zipFlags,
+		"outDir":         outDir.String(),
+		"mergeZipsFlags": mergeZipsFlags,
+	}
 	if useR8 {
 		proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary")
 		d.proguardDictionary = android.OptionalPathForPath(proguardDictionary)
@@ -511,25 +602,17 @@
 		d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip)
 		resourcesOutput := android.PathForModuleOut(ctx, "package-res-shrunken.apk")
 		d.resourcesOutput = android.OptionalPathForPath(resourcesOutput)
-		implicitOutputs := android.WritablePaths{
+		implicitOutputs = append(implicitOutputs, android.WritablePaths{
 			proguardDictionary,
 			proguardUsageZip,
 			proguardConfiguration,
-		}
+		}...)
+		description = "r8"
 		debugMode := android.InList("--debug", commonFlags)
 		r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams, debugMode)
-		rule := r8
-		args := map[string]string{
-			"r8Flags":        strings.Join(append(commonFlags, r8Flags...), " "),
-			"zipFlags":       zipFlags,
-			"outDict":        proguardDictionary.String(),
-			"outConfig":      proguardConfiguration.String(),
-			"outUsageDir":    proguardUsageDir.String(),
-			"outUsage":       proguardUsage.String(),
-			"outUsageZip":    proguardUsageZip.String(),
-			"outDir":         outDir.String(),
-			"mergeZipsFlags": mergeZipsFlags,
-		}
+		flags = append(flags, r8Flags...)
+		deps = append(deps, r8Deps...)
+		args["r8Flags"] = strings.Join(append(commonFlags, r8Flags...), " ")
 		if r8ArtProfileOutputPath != nil {
 			artProfileOutputPath = r8ArtProfileOutputPath
 			implicitOutputs = append(
@@ -540,27 +623,29 @@
 			// about this implicit output
 			args["outR8ArtProfile"] = artProfileOutputPath.String()
 		}
-
-		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
-			rule = r8RE
-			args["implicits"] = strings.Join(r8Deps.Strings(), ",")
-		}
+		args["outDict"] = proguardDictionary.String()
+		args["outConfig"] = proguardConfiguration.String()
+		args["outUsageDir"] = proguardUsageDir.String()
+		args["outUsage"] = proguardUsage.String()
+		args["outUsageZip"] = proguardUsageZip.String()
 		if d.resourcesInput.Valid() {
 			implicitOutputs = append(implicitOutputs, resourcesOutput)
 			args["resourcesOutput"] = resourcesOutput.String()
 		}
-		ctx.Build(pctx, android.BuildParams{
-			Rule:            rule,
-			Description:     "r8",
-			Output:          javalibJar,
-			ImplicitOutputs: implicitOutputs,
-			Input:           dexParams.classesJar,
-			Implicits:       r8Deps,
-			Args:            args,
-		})
-	} else {
-		implicitOutputs := android.WritablePaths{}
+
+		rule = r8
+		if rbeR8 {
+			rule = r8RE
+			args["implicits"] = strings.Join(deps.Strings(), ",")
+		}
+	}
+	if useD8 {
+		description = "d8"
 		d8Flags, d8Deps, d8ArtProfileOutputPath := d.d8Flags(ctx, dexParams)
+		flags = append(flags, d8Flags...)
+		deps = append(deps, d8Deps...)
+		deps = append(deps, commonDeps...)
+		args["d8Flags"] = strings.Join(append(commonFlags, d8Flags...), " ")
 		if d8ArtProfileOutputPath != nil {
 			artProfileOutputPath = d8ArtProfileOutputPath
 			implicitOutputs = append(
@@ -568,26 +653,42 @@
 				artProfileOutputPath,
 			)
 		}
-		d8Deps = append(d8Deps, commonDeps...)
-		rule := d8
-		if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") {
+		// If we are generating both d8 and r8, only use RBE when both are enabled.
+		switch {
+		case useR8 && rule == r8:
+			rule = d8r8
+			description = "d8r8"
+		case useR8 && rule == r8RE && rbeD8:
+			rule = d8r8RE
+			description = "d8r8"
+		case rbeD8:
 			rule = d8RE
+		default:
+			rule = d8
 		}
-		ctx.Build(pctx, android.BuildParams{
-			Rule:            rule,
-			Description:     "d8",
-			Output:          javalibJar,
-			Input:           dexParams.classesJar,
-			ImplicitOutputs: implicitOutputs,
-			Implicits:       d8Deps,
-			Args: map[string]string{
-				"d8Flags":        strings.Join(append(commonFlags, d8Flags...), " "),
-				"zipFlags":       zipFlags,
-				"outDir":         outDir.String(),
-				"mergeZipsFlags": mergeZipsFlags,
-			},
-		})
 	}
+	ctx.Build(pctx, android.BuildParams{
+		Rule:            rule,
+		Description:     description,
+		Output:          javalibJar,
+		ImplicitOutputs: implicitOutputs,
+		Input:           dexParams.classesJar,
+		Implicits:       deps,
+		Args:            args,
+	})
+	if useR8 && useD8 {
+		// Generate the rule for partial compile clean.
+		args["builtOut"] = javalibJar.String()
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        d8r8Clean,
+			Description: "d8r8Clean",
+			Output:      cleanPhonyPath,
+			Args:        args,
+			PhonyOutput: true,
+		})
+		ctx.Phony("partialcompileclean", cleanPhonyPath)
+	}
+
 	if proptools.Bool(d.dexProperties.Uncompress_dex) {
 		alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", dexParams.jarName).OutputPath
 		TransformZipAlign(ctx, alignedJavalibJar, javalibJar, nil)
diff --git a/java/java.go b/java/java.go
index 0a4a771..45e55d5 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1922,6 +1922,10 @@
 		if j.testConfig != nil {
 			ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".config", j.testConfig)
 		}
+		dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml")
+		if dynamicConfig.Valid() {
+			ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path())
+		}
 		testDeps := append(j.data, j.extraTestConfigs...)
 		for _, data := range android.SortedUniquePaths(testDeps) {
 			dataPath := android.DataPath{SrcPath: data}
diff --git a/python/binary.go b/python/binary.go
index 4d6e118..feac72a 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -114,6 +114,12 @@
 	android.SetProvider(ctx, PythonBinaryInfoProvider, PythonBinaryInfo{})
 
 	ctx.SetOutputFiles(android.Paths{p.installSource}, "")
+
+	moduleInfoJSON := ctx.ModuleInfoJSON()
+	moduleInfoJSON.Class = []string{"EXECUTABLES"}
+	moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, p.androidMkSharedLibs...)
+	moduleInfoJSON.SharedLibs = append(moduleInfoJSON.SharedLibs, p.androidMkSharedLibs...)
+	moduleInfoJSON.SystemSharedLibs = []string{"none"}
 }
 
 func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) {
diff --git a/python/test.go b/python/test.go
index 5e70fc1..df62ab7 100644
--- a/python/test.go
+++ b/python/test.go
@@ -224,6 +224,10 @@
 			if p.testConfig != nil {
 				ctx.InstallFile(testCases, ctx.ModuleName()+".config", p.testConfig)
 			}
+			dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml")
+			if dynamicConfig.Valid() {
+				ctx.InstallFile(testCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path())
+			}
 		}
 		// Install tests and data in arch specific subdir $PRODUCT_OUT/testcases/$module/$arch
 		testCases = testCases.Join(ctx, ctx.Target().Arch.ArchType.String())
diff --git a/rust/test.go b/rust/test.go
index b658ae2..5c183bc 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -208,6 +208,10 @@
 			if test.testConfig != nil {
 				ctx.InstallFile(testCases, ctx.ModuleName()+".config", test.testConfig)
 			}
+			dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml")
+			if dynamicConfig.Valid() {
+				ctx.InstallFile(testCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path())
+			}
 		}
 		// Install tests and data in arch specific subdir $PRODUCT_OUT/testcases/$module/$arch
 		testCases = testCases.Join(ctx, ctx.Target().Arch.ArchType.String())
diff --git a/scripts/strip.sh b/scripts/strip.sh
index 8d69f0d..5320ef6 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -101,7 +101,12 @@
 do_strip_keep_mini_debug_info_linux() {
     rm -f "${outfile}.mini_debuginfo.xz"
     local fail=
-    "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
+    if [ -z "${windows}" ]; then
+        "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
+    else
+        # --keep-section not supported for Windows COFF.
+        fail=true
+    fi
 
     if [ -z $fail ]; then
         # create_minidebuginfo has issues with compressed debug sections. Just
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 2da7328..c0c6ff2 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -544,6 +544,28 @@
 		MkAppClass:           mkEntries.Class,
 		InstallDir:           s.installDir,
 	})
+
+	moduleInfoJSON := ctx.ModuleInfoJSON()
+	moduleInfoJSON.Class = []string{"NATIVE_TESTS"}
+	if len(s.testProperties.Test_suites) > 0 {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, s.testProperties.Test_suites...)
+	} else {
+		moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite")
+	}
+	if proptools.Bool(s.testProperties.Test_options.Unit_test) {
+		moduleInfoJSON.IsUnitTest = "true"
+		if ctx.Host() {
+			moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests")
+		}
+	}
+	moduleInfoJSON.DataDependencies = append(moduleInfoJSON.DataDependencies, s.testProperties.Data_bins...)
+	if s.testConfig != nil {
+		if _, ok := s.testConfig.(android.WritablePath); ok {
+			moduleInfoJSON.AutoTestConfig = []string{"true"}
+		}
+		moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, s.testConfig.String())
+	}
+	moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, s.extraTestConfigs.Strings()...)
 }
 
 func addArch(archType string, paths android.Paths) []string {