Merge "Call clang-tidy with -fno-caret-diagnostics by default."
diff --git a/Android.bp b/Android.bp
index ba71789..91e73aa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -219,6 +219,7 @@
         "java/app_builder.go",
         "java/app.go",
         "java/builder.go",
+        "java/dex.go",
         "java/gen.go",
         "java/genrule.go",
         "java/jacoco.go",
diff --git a/android/config.go b/android/config.go
index 07e25f3..2ed6413 100644
--- a/android/config.go
+++ b/android/config.go
@@ -299,7 +299,10 @@
 func (c *config) fromEnv() error {
 	switch c.Getenv("EXPERIMENTAL_USE_OPENJDK9") {
 	case "":
-		// Use OpenJDK8
+		if c.Getenv("RUN_ERROR_PRONE") != "true" {
+			// Use OpenJDK9, but target 1.8
+			c.useOpenJDK9 = true
+		}
 	case "false":
 		// Use OpenJDK8
 	case "1.8":
@@ -310,7 +313,7 @@
 		c.useOpenJDK9 = true
 		c.targetOpenJDK9 = true
 	default:
-		return fmt.Errorf(`Invalid value for EXPERIMENTAL_USE_OPENJDK9, should be "", "1.8", or "true"`)
+		return fmt.Errorf(`Invalid value for EXPERIMENTAL_USE_OPENJDK9, should be "", "false", "1.8", or "true"`)
 	}
 
 	return nil
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index 82b5eb9..3e134b6 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -53,6 +53,7 @@
 	"LOCAL_SANITIZE_DIAG":         sanitize("diag."),
 	"LOCAL_CFLAGS":                cflags,
 	"LOCAL_UNINSTALLABLE_MODULE":  invert("installable"),
+	"LOCAL_PROGUARD_ENABLED":      proguardEnabled,
 
 	// composite functions
 	"LOCAL_MODULE_TAGS": includeVariableIf(bpVariable{"tags", bpparser.ListType}, not(valueDumpEquals("optional"))),
@@ -136,6 +137,9 @@
 
 			"LOCAL_ANNOTATION_PROCESSORS":        "annotation_processors",
 			"LOCAL_ANNOTATION_PROCESSOR_CLASSES": "annotation_processor_classes",
+
+			"LOCAL_PROGUARD_FLAGS":      "optimize.proguard_flags",
+			"LOCAL_PROGUARD_FLAG_FILES": "optimize.proguard_flag_files",
 		})
 	addStandardProperties(bpparser.BoolType,
 		map[string]string{
@@ -517,6 +521,60 @@
 	return includeVariableNow(bpVariable{"cflags", bpparser.ListType}, ctx)
 }
 
+func proguardEnabled(ctx variableAssignmentContext) error {
+	val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.ListType)
+	if err != nil {
+		return err
+	}
+
+	list, ok := val.(*bpparser.List)
+	if !ok {
+		return fmt.Errorf("unsupported proguard expression")
+	}
+
+	set := func(prop string, value bool) {
+		bpValue := &bpparser.Bool{
+			Value: value,
+		}
+		setVariable(ctx.file, false, ctx.prefix, prop, bpValue, true)
+	}
+
+	enable := false
+
+	for _, v := range list.Values {
+		s, ok := v.(*bpparser.String)
+		if !ok {
+			return fmt.Errorf("unsupported proguard expression")
+		}
+
+		switch s.Value {
+		case "disabled":
+			set("optimize.enabled", false)
+		case "obfuscation":
+			enable = true
+			set("optimize.obfuscate", true)
+		case "optimization":
+			enable = true
+			set("optimize.optimize", true)
+		case "full":
+			enable = true
+		case "custom":
+			set("optimize.no_aapt_flags", true)
+			enable = true
+		default:
+			return fmt.Errorf("unsupported proguard value %q", s)
+		}
+	}
+
+	if enable {
+		// This is only necessary for libraries which default to false, but we can't
+		// tell the difference between a library and an app here.
+		set("optimize.enabled", true)
+	}
+
+	return nil
+}
+
 func invert(name string) func(ctx variableAssignmentContext) error {
 	return func(ctx variableAssignmentContext) error {
 		val, err := makeVariableToBlueprint(ctx.file, ctx.mkvalue, bpparser.BoolType)
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 22a52d4..c85aaaa 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -438,6 +438,42 @@
 `,
 		expected: ``,
 	},
+	{
+		desc: "proguard options for java library",
+		in: `
+			include $(CLEAR_VARS)
+			# Empty
+			LOCAL_PROGUARD_ENABLED :=
+			# Disabled
+			LOCAL_PROGUARD_ENABLED := disabled
+			# Full
+			LOCAL_PROGUARD_ENABLED := full
+			# Obfuscation and optimization
+			LOCAL_PROGUARD_ENABLED := obfuscation optimization
+			# Custom
+			LOCAL_PROGUARD_ENABLED := custom
+			include $(BUILD_JAVA_LIBRARY)
+		`,
+		expected: `
+			java_library {
+				// Empty
+
+				// Disabled
+				optimize: {
+					enabled: false,
+					// Full
+					enabled: true,
+					// Obfuscation and optimization
+					obfuscate: true,
+					optimize: true,
+					enabled: true,
+					// Custom
+					no_aapt_flags: true,
+					enabled: true,
+				},
+			}
+		`,
+	},
 }
 
 func reformatBlueprint(input string) string {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index efd4ee7..e78c419 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -355,7 +355,7 @@
 func (c *vndkPrebuiltLibraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	ret.Class = "SHARED_LIBRARIES"
 
-	ret.SubName = vndkSuffix + c.version()
+	ret.SubName = c.NameSuffix()
 
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		c.libraryDecorator.androidMkWriteExportedFlags(w)
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 9ccab03..b4fcb57 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -47,8 +47,11 @@
 // }
 //
 type vndkPrebuiltProperties struct {
-	// VNDK snapshot version that is formated as {SDK_ver}.{Major}.{Minor}.
-	Version string
+	// VNDK snapshot version.
+	Version *string
+
+	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab')
+	Target_arch *string
 
 	// Prebuilt files for each arch.
 	Srcs []string `android:"arch_variant"`
@@ -60,15 +63,26 @@
 }
 
 func (p *vndkPrebuiltLibraryDecorator) Name(name string) string {
-	return name + vndkSuffix + p.version()
+	return name + p.NameSuffix()
+}
+
+func (p *vndkPrebuiltLibraryDecorator) NameSuffix() string {
+	if p.arch() != "" {
+		return vndkSuffix + p.version() + "." + p.arch()
+	}
+	return vndkSuffix + p.version()
 }
 
 func (p *vndkPrebuiltLibraryDecorator) version() string {
-	return p.properties.Version
+	return String(p.properties.Version)
+}
+
+func (p *vndkPrebuiltLibraryDecorator) arch() string {
+	return String(p.properties.Target_arch)
 }
 
 func (p *vndkPrebuiltLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
-	p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), vndkSuffix+p.version())
+	p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix())
 	return p.libraryDecorator.linkerFlags(ctx, flags)
 }
 
diff --git a/java/androidmk.go b/java/androidmk.go
index 24fe43a..64ef505 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -165,6 +165,9 @@
 				if app.jacocoReportClassesFile != nil {
 					fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", app.jacocoReportClassesFile.String())
 				}
+				if app.proguardDictionary != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_PROGUARD_DICT :=", app.proguardDictionary.String())
+				}
 
 				if app.Name() == "framework-res" {
 					fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
diff --git a/java/app.go b/java/app.go
index df53375..234dcb7 100644
--- a/java/app.go
+++ b/java/app.go
@@ -125,14 +125,13 @@
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
 
-	//if !ctx.ContainsProperty("proguard.enabled") {
-	//	a.properties.Proguard.Enabled = true
-	//}
-
 	if String(a.appProperties.Instrumentation_for) == "" {
 		a.properties.Instrument = true
 	}
 
+	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
+		proguardOptionsFile)
+
 	if ctx.ModuleName() != "framework-res" {
 		a.Module.compile(ctx, a.aaptSrcJar)
 	}
@@ -324,6 +323,9 @@
 func AndroidAppFactory() android.Module {
 	module := &AndroidApp{}
 
+	module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
+	module.Module.deviceProperties.Optimize.Shrink = proptools.BoolPtr(true)
+
 	module.AddProperties(
 		&module.Module.properties,
 		&module.Module.deviceProperties,
diff --git a/java/builder.go b/java/builder.go
index 56c7b33..bf826e1 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -135,46 +135,6 @@
 		},
 		"jarArgs")
 
-	desugar = pctx.AndroidStaticRule("desugar",
-		blueprint.RuleParams{
-			Command: `rm -rf $dumpDir && mkdir -p $dumpDir && ` +
-				`${config.JavaCmd} ` +
-				`-Djdk.internal.lambda.dumpProxyClasses=$$(cd $dumpDir && pwd) ` +
-				`$javaFlags ` +
-				`-jar ${config.DesugarJar} $classpathFlags $desugarFlags ` +
-				`-i $in -o $out`,
-			CommandDeps: []string{"${config.DesugarJar}", "${config.JavaCmd}"},
-		},
-		"javaFlags", "classpathFlags", "desugarFlags", "dumpDir")
-
-	dx = pctx.AndroidStaticRule("dx",
-		blueprint.RuleParams{
-			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
-				`${config.DxCmd} --dex --output=$outDir $dxFlags $in && ` +
-				`${config.SoongZipCmd} -o $outDir/classes.dex.jar -C $outDir -D $outDir && ` +
-				`${config.MergeZipsCmd} -D -stripFile "*.class" $out $outDir/classes.dex.jar $in`,
-			CommandDeps: []string{
-				"${config.DxCmd}",
-				"${config.SoongZipCmd}",
-				"${config.MergeZipsCmd}",
-			},
-		},
-		"outDir", "dxFlags")
-
-	d8 = pctx.AndroidStaticRule("d8",
-		blueprint.RuleParams{
-			Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
-				`${config.D8Cmd} --output $outDir $dxFlags $in && ` +
-				`${config.SoongZipCmd} -o $outDir/classes.dex.jar -C $outDir -D $outDir && ` +
-				`${config.MergeZipsCmd} -D -stripFile "*.class" $out $outDir/classes.dex.jar $in`,
-			CommandDeps: []string{
-				"${config.DxCmd}",
-				"${config.SoongZipCmd}",
-				"${config.MergeZipsCmd}",
-			},
-		},
-		"outDir", "dxFlags")
-
 	jarjar = pctx.AndroidStaticRule("jarjar",
 		blueprint.RuleParams{
 			Command:     "${config.JavaCmd} -jar ${config.JarjarCmd} process $rulesFile $in $out",
@@ -189,11 +149,9 @@
 
 type javaBuilderFlags struct {
 	javacFlags    string
-	dxFlags       string
 	bootClasspath classpath
 	classpath     classpath
 	systemModules classpath
-	desugarFlags  string
 	aidlFlags     string
 	javaVersion   string
 
@@ -403,64 +361,6 @@
 	})
 }
 
-func TransformDesugar(ctx android.ModuleContext, outputFile android.WritablePath,
-	classesJar android.Path, flags javaBuilderFlags) {
-
-	dumpDir := android.PathForModuleOut(ctx, "desugar", "classes")
-
-	javaFlags := ""
-	if ctx.Config().UseOpenJDK9() {
-		javaFlags = "--add-opens java.base/java.lang.invoke=ALL-UNNAMED"
-	}
-
-	var desugarFlags []string
-	desugarFlags = append(desugarFlags, flags.bootClasspath.FormDesugarClasspath("--bootclasspath_entry")...)
-	desugarFlags = append(desugarFlags, flags.classpath.FormDesugarClasspath("--classpath_entry")...)
-
-	var deps android.Paths
-	deps = append(deps, flags.bootClasspath...)
-	deps = append(deps, flags.classpath...)
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        desugar,
-		Description: "desugar",
-		Output:      outputFile,
-		Input:       classesJar,
-		Implicits:   deps,
-		Args: map[string]string{
-			"dumpDir":        dumpDir.String(),
-			"javaFlags":      javaFlags,
-			"classpathFlags": strings.Join(desugarFlags, " "),
-			"desugarFlags":   flags.desugarFlags,
-		},
-	})
-}
-
-// Converts a classes.jar file to classes*.dex, then combines the dex files with any resources
-// in the classes.jar file into a dex jar.
-func TransformClassesJarToDexJar(ctx android.ModuleContext, outputFile android.WritablePath,
-	classesJar android.Path, flags javaBuilderFlags) {
-
-	outDir := android.PathForModuleOut(ctx, "dex")
-
-	rule := dx
-	desc := "dx"
-	if ctx.Config().UseD8Desugar() {
-		rule = d8
-		desc = "d8"
-	}
-	ctx.Build(pctx, android.BuildParams{
-		Rule:        rule,
-		Description: desc,
-		Output:      outputFile,
-		Input:       classesJar,
-		Args: map[string]string{
-			"dxFlags": flags.dxFlags,
-			"outDir":  outDir.String(),
-		},
-	})
-}
-
 func TransformJarJar(ctx android.ModuleContext, outputFile android.WritablePath,
 	classesJar android.Path, rulesFile android.Path) {
 	ctx.Build(pctx, android.BuildParams{
diff --git a/java/config/config.go b/java/config/config.go
index c43f9a3..75176c9 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -106,13 +106,9 @@
 			return path.String(), nil
 		}
 	})
-	pctx.VariableFunc("D8Cmd", func(config android.Config) (string, error) {
-		path, err := pctx.HostBinToolPath(config, "d8")
-		if err != nil {
-			return "", err
-		}
-		return path.String(), nil
-	})
+	pctx.HostBinToolVariable("D8Cmd", "d8")
+	pctx.HostBinToolVariable("R8Cmd", "r8-compat-proguard")
+
 	pctx.VariableFunc("TurbineJar", func(config android.Config) (string, error) {
 		turbine := "turbine.jar"
 		if config.UnbundledBuild() {
diff --git a/java/config/makevars.go b/java/config/makevars.go
index c382cc1..7e125d5 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -55,6 +55,7 @@
 		ctx.Strict("DX_COMMAND", "${DxCmd} -JXms16M -JXmx2048M")
 		ctx.Strict("USE_D8_DESUGAR", "false")
 	}
+	ctx.Strict("R8_COMPAT_PROGUARD", "${R8Cmd}")
 
 	ctx.Strict("TURBINE", "${TurbineJar}")
 
diff --git a/java/dex.go b/java/dex.go
new file mode 100644
index 0000000..2beb2ac
--- /dev/null
+++ b/java/dex.go
@@ -0,0 +1,272 @@
+// Copyright 2017 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 java
+
+import (
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+var desugar = pctx.AndroidStaticRule("desugar",
+	blueprint.RuleParams{
+		Command: `rm -rf $dumpDir && mkdir -p $dumpDir && ` +
+			`${config.JavaCmd} ` +
+			`-Djdk.internal.lambda.dumpProxyClasses=$$(cd $dumpDir && pwd) ` +
+			`$javaFlags ` +
+			`-jar ${config.DesugarJar} $classpathFlags $desugarFlags ` +
+			`-i $in -o $out`,
+		CommandDeps: []string{"${config.DesugarJar}", "${config.JavaCmd}"},
+	},
+	"javaFlags", "classpathFlags", "desugarFlags", "dumpDir")
+
+func (j *Module) desugar(ctx android.ModuleContext, flags javaBuilderFlags,
+	classesJar android.Path, jarName string) android.Path {
+
+	desugarFlags := []string{
+		"--min_sdk_version " + j.minSdkVersionNumber(ctx),
+		"--desugar_try_with_resources_if_needed=false",
+		"--allow_empty_bootclasspath",
+	}
+
+	if inList("--core-library", j.deviceProperties.Dxflags) {
+		desugarFlags = append(desugarFlags, "--core_library")
+	}
+
+	desugarJar := android.PathForModuleOut(ctx, "desugar", jarName)
+	dumpDir := android.PathForModuleOut(ctx, "desugar", "classes")
+
+	javaFlags := ""
+	if ctx.Config().UseOpenJDK9() {
+		javaFlags = "--add-opens java.base/java.lang.invoke=ALL-UNNAMED"
+	}
+
+	var classpathFlags []string
+	classpathFlags = append(classpathFlags, flags.bootClasspath.FormDesugarClasspath("--bootclasspath_entry")...)
+	classpathFlags = append(classpathFlags, flags.classpath.FormDesugarClasspath("--classpath_entry")...)
+
+	var deps android.Paths
+	deps = append(deps, flags.bootClasspath...)
+	deps = append(deps, flags.classpath...)
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        desugar,
+		Description: "desugar",
+		Output:      desugarJar,
+		Input:       classesJar,
+		Implicits:   deps,
+		Args: map[string]string{
+			"dumpDir":        dumpDir.String(),
+			"javaFlags":      javaFlags,
+			"classpathFlags": strings.Join(classpathFlags, " "),
+			"desugarFlags":   strings.Join(desugarFlags, " "),
+		},
+	})
+
+	return desugarJar
+}
+
+var dx = pctx.AndroidStaticRule("dx",
+	blueprint.RuleParams{
+		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
+			`${config.DxCmd} --dex --output=$outDir $dxFlags $in && ` +
+			`${config.SoongZipCmd} -o $outDir/classes.dex.jar -C $outDir -D $outDir && ` +
+			`${config.MergeZipsCmd} -D -stripFile "*.class" $out $outDir/classes.dex.jar $in`,
+		CommandDeps: []string{
+			"${config.DxCmd}",
+			"${config.SoongZipCmd}",
+			"${config.MergeZipsCmd}",
+		},
+	},
+	"outDir", "dxFlags")
+
+var d8 = pctx.AndroidStaticRule("d8",
+	blueprint.RuleParams{
+		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
+			`${config.D8Cmd} --output $outDir $dxFlags $in && ` +
+			`${config.SoongZipCmd} -o $outDir/classes.dex.jar -C $outDir -D $outDir && ` +
+			`${config.MergeZipsCmd} -D -stripFile "*.class" $out $outDir/classes.dex.jar $in`,
+		CommandDeps: []string{
+			"${config.D8Cmd}",
+			"${config.SoongZipCmd}",
+			"${config.MergeZipsCmd}",
+		},
+	},
+	"outDir", "dxFlags")
+
+var r8 = pctx.AndroidStaticRule("r8",
+	blueprint.RuleParams{
+		Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
+			`${config.R8Cmd} -injars $in --output $outDir ` +
+			`--force-proguard-compatibility ` +
+			`-printmapping $outDict ` +
+			`$dxFlags $r8Flags && ` +
+			`${config.SoongZipCmd} -o $outDir/classes.dex.jar -C $outDir -D $outDir && ` +
+			`${config.MergeZipsCmd} -D -stripFile "*.class" $out $outDir/classes.dex.jar $in`,
+		CommandDeps: []string{
+			"${config.R8Cmd}",
+			"${config.SoongZipCmd}",
+			"${config.MergeZipsCmd}",
+		},
+	},
+	"outDir", "outDict", "dxFlags", "r8Flags")
+
+func (j *Module) dxFlags(ctx android.ModuleContext, fullD8 bool) []string {
+	flags := j.deviceProperties.Dxflags
+	if fullD8 {
+		// Translate all the DX flags to D8 ones until all the build files have been migrated
+		// to D8 flags. See: b/69377755
+		flags = android.RemoveListFromList(flags,
+			[]string{"--core-library", "--dex", "--multi-dex"})
+	}
+
+	if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" {
+		if fullD8 {
+			flags = append(flags, "--debug")
+		} else {
+			flags = append(flags, "--no-optimize")
+		}
+	}
+
+	if ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" {
+		flags = append(flags,
+			"--debug",
+			"--verbose")
+		if !fullD8 {
+			flags = append(flags,
+				"--dump-to="+android.PathForModuleOut(ctx, "classes.lst").String(),
+				"--dump-width=1000")
+		}
+	}
+
+	if fullD8 {
+		flags = append(flags, "--min-api "+j.minSdkVersionNumber(ctx))
+	} else {
+		flags = append(flags, "--min-sdk-version="+j.minSdkVersionNumber(ctx))
+	}
+	return flags
+}
+
+func (j *Module) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Flags []string, r8Deps android.Paths) {
+	opt := j.deviceProperties.Optimize
+
+	// When an app contains references to APIs that are not in the SDK specified by
+	// its LOCAL_SDK_VERSION for example added by support library or by runtime
+	// classes added by desugar, we artifically raise the "SDK version" "linked" by
+	// ProGuard, to
+	// - suppress ProGuard warnings of referencing symbols unknown to the lower SDK version.
+	// - prevent ProGuard stripping subclass in the support library that extends class added in the higher SDK version.
+	// See b/20667396
+	var proguardRaiseDeps classpath
+	ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(dep android.Module) {
+		proguardRaiseDeps = append(proguardRaiseDeps, dep.(Dependency).HeaderJars()...)
+	})
+
+	r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
+	r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars"))
+	r8Flags = append(r8Flags, flags.classpath.FormJavaClassPath("-libraryjars"))
+	r8Flags = append(r8Flags, "-forceprocessing")
+
+	flagFiles := android.Paths{
+		android.PathForSource(ctx, "build/make/core/proguard.flags"),
+	}
+
+	flagFiles = append(flagFiles, j.extraProguardFlagFiles...)
+	// TODO(ccross): static android library proguard files
+
+	r8Flags = append(r8Flags, android.JoinWithPrefix(flagFiles.Strings(), "-include "))
+	r8Deps = append(r8Deps, flagFiles...)
+
+	// TODO(b/70942988): This is included from build/make/core/proguard.flags
+	r8Deps = append(r8Deps, android.PathForSource(ctx,
+		"build/make/core/proguard_basic_keeps.flags"))
+
+	r8Flags = append(r8Flags, j.deviceProperties.Optimize.Proguard_flags...)
+
+	// TODO(ccross): Don't shrink app instrumentation tests by default.
+	if !Bool(opt.Shrink) {
+		r8Flags = append(r8Flags, "-dontshrink")
+	}
+
+	if !Bool(opt.Optimize) {
+		r8Flags = append(r8Flags, "-dontoptimize")
+	}
+
+	// TODO(ccross): error if obufscation + app instrumentation test.
+	if !Bool(opt.Obfuscate) {
+		r8Flags = append(r8Flags, "-dontobfuscate")
+	}
+
+	return r8Flags, r8Deps
+}
+
+func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
+	classesJar android.Path, jarName string) android.Path {
+
+	useR8 := Bool(j.deviceProperties.Optimize.Enabled)
+	fullD8 := useR8 || ctx.Config().UseD8Desugar()
+
+	if !fullD8 {
+		classesJar = j.desugar(ctx, flags, classesJar, jarName)
+	}
+
+	dxFlags := j.dxFlags(ctx, fullD8)
+
+	// Compile classes.jar into classes.dex and then javalib.jar
+	javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
+	outDir := android.PathForModuleOut(ctx, "dex")
+
+	if useR8 {
+		// TODO(ccross): if this is an instrumentation test of an obfuscated app, use the
+		// dictionary of the app and move the app from libraryjars to injars.
+		j.proguardDictionary = android.PathForModuleOut(ctx, "proguard_dictionary")
+		r8Flags, r8Deps := j.r8Flags(ctx, flags)
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        r8,
+			Description: "r8",
+			Output:      javalibJar,
+			Input:       classesJar,
+			Implicits:   r8Deps,
+			Args: map[string]string{
+				"dxFlags": strings.Join(dxFlags, " "),
+				"r8Flags": strings.Join(r8Flags, " "),
+				"outDict": j.proguardDictionary.String(),
+				"outDir":  outDir.String(),
+			},
+		})
+	} else {
+		rule := dx
+		desc := "dx"
+		if fullD8 {
+			rule = d8
+			desc = "d8"
+		}
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        rule,
+			Description: desc,
+			Output:      javalibJar,
+			Input:       classesJar,
+			Args: map[string]string{
+				"dxFlags": strings.Join(dxFlags, " "),
+				"outDir":  outDir.String(),
+			},
+		})
+	}
+
+	j.dexJarFile = javalibJar
+	return javalibJar
+}
diff --git a/java/jacoco.go b/java/jacoco.go
index 59f2fd3..8f1ceb2 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -18,6 +18,7 @@
 
 import (
 	"fmt"
+	"path/filepath"
 	"strings"
 
 	"github.com/google/blueprint"
@@ -27,10 +28,12 @@
 
 var (
 	jacoco = pctx.AndroidStaticRule("jacoco", blueprint.RuleParams{
-		Command: `${config.Zip2ZipCmd} -i $in -o $strippedJar $stripSpec && ` +
-			`${config.JavaCmd} -jar ${config.JacocoCLIJar} instrument -quiet -dest $instrumentedJar $strippedJar && ` +
-			`${config.Ziptime} $instrumentedJar && ` +
-			`${config.MergeZipsCmd} --ignore-duplicates -j $out $instrumentedJar $in`,
+		Command: `rm -rf $tmpDir && mkdir -p $tmpDir && ` +
+			`${config.Zip2ZipCmd} -i $in -o $strippedJar $stripSpec && ` +
+			`${config.JavaCmd} -jar ${config.JacocoCLIJar} ` +
+			`  instrument --quiet --dest $tmpDir $strippedJar && ` +
+			`${config.Ziptime} $tmpJar && ` +
+			`${config.MergeZipsCmd} --ignore-duplicates -j $out $tmpJar $in`,
 		CommandDeps: []string{
 			"${config.Zip2ZipCmd}",
 			"${config.JavaCmd}",
@@ -39,23 +42,30 @@
 			"${config.MergeZipsCmd}",
 		},
 	},
-		"strippedJar", "stripSpec", "instrumentedJar")
+		"strippedJar", "stripSpec", "tmpDir", "tmpJar")
 )
 
-func jacocoInstrumentJar(ctx android.ModuleContext, outputJar, strippedJar android.WritablePath,
+// Instruments a jar using the Jacoco command line interface.  Uses stripSpec to extract a subset
+// of the classes in inputJar into strippedJar, instruments strippedJar into tmpJar, and then
+// combines the classes in tmpJar with inputJar (preferring the instrumented classes in tmpJar)
+// to produce instrumentedJar.
+func jacocoInstrumentJar(ctx android.ModuleContext, instrumentedJar, strippedJar android.WritablePath,
 	inputJar android.Path, stripSpec string) {
-	instrumentedJar := android.PathForModuleOut(ctx, "jacoco/instrumented.jar")
+
+	// The basename of tmpJar has to be the same as the basename of strippedJar
+	tmpJar := android.PathForModuleOut(ctx, "jacoco", "tmp", strippedJar.Base())
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:           jacoco,
 		Description:    "jacoco",
-		Output:         outputJar,
+		Output:         instrumentedJar,
 		ImplicitOutput: strippedJar,
 		Input:          inputJar,
 		Args: map[string]string{
-			"strippedJar":     strippedJar.String(),
-			"stripSpec":       stripSpec,
-			"instrumentedJar": instrumentedJar.String(),
+			"strippedJar": strippedJar.String(),
+			"stripSpec":   stripSpec,
+			"tmpDir":      filepath.Dir(tmpJar.String()),
+			"tmpJar":      tmpJar.String(),
 		},
 	})
 }
diff --git a/java/java.go b/java/java.go
index 8159af8..24debac 100644
--- a/java/java.go
+++ b/java/java.go
@@ -191,6 +191,32 @@
 		Profile *string
 	}
 
+	Optimize struct {
+		// If false, disable all optimization.  Defaults to true for apps, false for
+		// libraries and tests.
+		Enabled *bool
+
+		// If true, optimize for size by removing unused code.  Defaults to true for apps,
+		// false for libraries and tests.
+		Shrink *bool
+
+		// If true, optimize bytecode.  Defaults to false.
+		Optimize *bool
+
+		// If true, obfuscate bytecode.  Defaults to false.
+		Obfuscate *bool
+
+		// If true, do not use the flag files generated by aapt that automatically keep
+		// classes referenced by the app manifest.  Defaults to false.
+		No_aapt_flags *bool
+
+		// Flags to pass to proguard.
+		Proguard_flags []string
+
+		// Specifies the locations of files containing proguard flags.
+		Proguard_flags_files []string
+	}
+
 	// When targeting 1.9, override the modules to use with --system
 	System_modules *string
 }
@@ -216,6 +242,9 @@
 	// output file containing uninstrumented classes that will be instrumented by jacoco
 	jacocoReportClassesFile android.Path
 
+	// output file containing mapping of obfuscated names
+	proguardDictionary android.Path
+
 	// output file suitable for installing or running
 	outputFile android.Path
 
@@ -229,6 +258,9 @@
 	// list of .java files and srcjars that was passed to javac
 	compiledJavaSrcs android.Paths
 	compiledSrcJars  android.Paths
+
+	// list of extra progurad flag files
+	extraProguardFlagFiles android.Paths
 }
 
 func (j *Module) Srcs() android.Paths {
@@ -260,6 +292,7 @@
 	systemModulesTag = dependencyTag{name: "system modules"}
 	frameworkResTag  = dependencyTag{name: "framework-res"}
 	kotlinStdlibTag  = dependencyTag{name: "kotlin-stdlib"}
+	proguardRaiseTag = dependencyTag{name: "proguard-raise"}
 )
 
 type sdkDep struct {
@@ -377,6 +410,10 @@
 					ctx.AddDependency(ctx.Module(), systemModulesTag, sdkDep.systemModules)
 				}
 				ctx.AddDependency(ctx.Module(), bootClasspathTag, sdkDep.module)
+				if Bool(j.deviceProperties.Optimize.Enabled) {
+					ctx.AddDependency(ctx.Module(), proguardRaiseTag, config.DefaultBootclasspathLibraries...)
+					ctx.AddDependency(ctx.Module(), proguardRaiseTag, config.DefaultLibraries...)
+				}
 			}
 		} else if j.deviceProperties.System_modules == nil {
 			ctx.PropertyErrorf("no_standard_libs",
@@ -700,7 +737,6 @@
 	// Store the list of .java files that was passed to javac
 	j.compiledJavaSrcs = uniqueSrcFiles
 	j.compiledSrcJars = srcJars
-	fullD8 := ctx.Config().UseD8Desugar()
 
 	enable_sharding := false
 	if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") {
@@ -829,10 +865,6 @@
 		j.headerJarFile = j.implementationJarFile
 	}
 
-	if !fullD8 && ctx.Device() && j.installable() {
-		outputFile = j.desugar(ctx, flags, outputFile, jarName)
-	}
-
 	if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
 		if inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
 			j.properties.Instrument = true
@@ -844,11 +876,7 @@
 	}
 
 	if ctx.Device() && j.installable() {
-		if fullD8 {
-			outputFile = j.compileDexFullD8(ctx, flags, outputFile, jarName)
-		} else {
-			outputFile = j.compileDex(ctx, flags, outputFile, jarName)
-		}
+		outputFile = j.compileDex(ctx, flags, outputFile, jarName)
 		if ctx.Failed() {
 			return
 		}
@@ -896,33 +924,12 @@
 	return headerJar
 }
 
-func (j *Module) desugar(ctx android.ModuleContext, flags javaBuilderFlags,
-	classesJar android.Path, jarName string) android.Path {
-
-	desugarFlags := []string{
-		"--min_sdk_version " + j.minSdkVersionNumber(ctx),
-		"--desugar_try_with_resources_if_needed=false",
-		"--allow_empty_bootclasspath",
-	}
-
-	if inList("--core-library", j.deviceProperties.Dxflags) {
-		desugarFlags = append(desugarFlags, "--core_library")
-	}
-
-	flags.desugarFlags = strings.Join(desugarFlags, " ")
-
-	desugarJar := android.PathForModuleOut(ctx, "desugar", jarName)
-	TransformDesugar(ctx, desugarJar, classesJar, flags)
-
-	return desugarJar
-}
-
 func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
 	classesJar android.Path, jarName string) android.Path {
 
 	specs := j.jacocoModuleToZipCommand(ctx)
 
-	jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco", "jacoco-report-classes.jar")
+	jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco-report-classes", jarName)
 	instrumentedJar := android.PathForModuleOut(ctx, "jacoco", jarName)
 
 	jacocoInstrumentJar(ctx, instrumentedJar, jacocoReportClassesFile, classesJar, specs)
@@ -932,72 +939,6 @@
 	return instrumentedJar
 }
 
-func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
-	classesJar android.Path, jarName string) android.Path {
-
-	dxFlags := j.deviceProperties.Dxflags
-
-	if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" {
-		dxFlags = append(dxFlags, "--no-optimize")
-	}
-
-	if ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" {
-		dxFlags = append(dxFlags,
-			"--debug",
-			"--verbose",
-			"--dump-to="+android.PathForModuleOut(ctx, "classes.lst").String(),
-			"--dump-width=1000")
-	}
-
-	dxFlags = append(dxFlags, "--min-sdk-version="+j.minSdkVersionNumber(ctx))
-
-	flags.dxFlags = strings.Join(dxFlags, " ")
-
-	// Compile classes.jar into classes.dex and then javalib.jar
-	javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
-	TransformClassesJarToDexJar(ctx, javalibJar, classesJar, flags)
-
-	j.dexJarFile = javalibJar
-	return javalibJar
-}
-
-func (j *Module) compileDexFullD8(ctx android.ModuleContext, flags javaBuilderFlags,
-	classesJar android.Path, jarName string) android.Path {
-
-	// Translate all the DX flags to D8 ones until all the build files have been migrated
-	// to D8 flags. See: b/69377755
-	var dxFlags []string
-	for _, x := range j.deviceProperties.Dxflags {
-		switch x {
-		case "--core-library", "--dex", "--multi-dex":
-			continue
-		default:
-			dxFlags = append(dxFlags, x)
-		}
-	}
-
-	if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
-		dxFlags = append(dxFlags, "--debug")
-	}
-
-	if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" {
-		dxFlags = append(dxFlags,
-			"--debug",
-			"--verbose")
-	}
-
-	dxFlags = append(dxFlags, "--min-api "+j.minSdkVersionNumber(ctx))
-
-	flags.dxFlags = strings.Join(dxFlags, " ")
-
-	// Compile classes.jar into classes.dex and then javalib.jar
-	javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
-	TransformClassesJarToDexJar(ctx, javalibJar, classesJar, flags)
-
-	j.dexJarFile = javalibJar
-	return javalibJar
-}
-
 // Returns a sdk version as a string that is guaranteed to be a parseable as a number.  For
 // modules targeting an unreleased SDK (meaning it does not yet have a number) it returns "10000".
 func (j *Module) minSdkVersionNumber(ctx android.ModuleContext) string {
diff --git a/java/java_test.go b/java/java_test.go
index 6e14a70..e8298a2 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -157,6 +157,9 @@
 
 		"build/soong/scripts/jar-wrapper.sh": nil,
 
+		"build/make/core/proguard.flags":             nil,
+		"build/make/core/proguard_basic_keeps.flags": nil,
+
 		"jdk8/jre/lib/jce.jar": nil,
 		"jdk8/jre/lib/rt.jar":  nil,
 	}
diff --git a/ui/build/config.go b/ui/build/config.go
index c975243..f2511e7 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -152,7 +152,16 @@
 		if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok {
 			return override
 		}
-		if v, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK9"); ok && v != "" && v != "false" {
+		v, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK9")
+		if !ok {
+			v2, ok2 := ret.environ.Get("RUN_ERROR_PRONE")
+			if ok2 && (v2 == "true") {
+				v = "false"
+			} else {
+				v = "1.8"
+			}
+		}
+		if v != "false" {
 			return java9Home
 		}
 		return java8Home