Merge "Revert "Remove armv7-a without neon support""
diff --git a/android/config.go b/android/config.go
index 9217aab..7d2e829 100644
--- a/android/config.go
+++ b/android/config.go
@@ -948,6 +948,8 @@
 	return "", false
 }
 
+// SecondArchIsTranslated returns true if the primary device arch is X86 or X86_64 and the device also has an arch
+// that is Arm or Arm64.
 func (c *config) SecondArchIsTranslated() bool {
 	deviceTargets := c.Targets[Android]
 	if len(deviceTargets) < 2 {
@@ -956,8 +958,7 @@
 
 	arch := deviceTargets[0].Arch
 
-	return (arch.ArchType == X86 || arch.ArchType == X86_64) &&
-		(hasArmAbi(arch) || hasArmAndroidArch(deviceTargets))
+	return (arch.ArchType == X86 || arch.ArchType == X86_64) && hasArmAndroidArch(deviceTargets)
 }
 
 func (c *config) IntegerOverflowDisabledForPath(path string) bool {
diff --git a/android/makevars.go b/android/makevars.go
index 2c2fb6f..c011ea6 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -90,6 +90,25 @@
 	makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
 }
 
+// SingletonMakeVarsProvider is a Singleton with an extra method to provide extra values to be exported to Make.
+type SingletonMakeVarsProvider interface {
+	Singleton
+
+	// MakeVars uses a MakeVarsContext to provide extra values to be exported to Make.
+	MakeVars(ctx MakeVarsContext)
+}
+
+// registerSingletonMakeVarsProvider adds a singleton that implements SingletonMakeVarsProvider to the list of
+// MakeVarsProviders to run.
+func registerSingletonMakeVarsProvider(singleton SingletonMakeVarsProvider) {
+	makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, SingletonmakeVarsProviderAdapter(singleton)})
+}
+
+// SingletonmakeVarsProviderAdapter converts a SingletonMakeVarsProvider to a MakeVarsProvider.
+func SingletonmakeVarsProviderAdapter(singleton SingletonMakeVarsProvider) MakeVarsProvider {
+	return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 func makeVarsSingletonFunc() Singleton {
diff --git a/android/onceper.go b/android/onceper.go
index f06f428..5ad17fa 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -70,7 +70,7 @@
 		panic(fmt.Errorf("Get() called before Once()"))
 	}
 
-	return v
+	return once.maybeWaitFor(key, v)
 }
 
 // OnceStringSlice is the same as Once, but returns the value cast to a []string
diff --git a/android/onceper_test.go b/android/onceper_test.go
index f27799b..95303ba 100644
--- a/android/onceper_test.go
+++ b/android/onceper_test.go
@@ -16,6 +16,7 @@
 
 import (
 	"testing"
+	"time"
 )
 
 func TestOncePer_Once(t *testing.T) {
@@ -34,6 +35,21 @@
 	}
 }
 
+func TestOncePer_Once_wait(t *testing.T) {
+	once := OncePer{}
+	key := NewOnceKey("key")
+
+	ch := make(chan bool)
+
+	go once.Once(key, func() interface{} { close(ch); time.Sleep(100 * time.Millisecond); return "foo" })
+	<-ch
+	a := once.Once(key, func() interface{} { return "bar" }).(string)
+
+	if a != "foo" {
+		t.Errorf("expect %q, got %q", "foo", a)
+	}
+}
+
 func TestOncePer_Get(t *testing.T) {
 	once := OncePer{}
 	key := NewOnceKey("key")
@@ -65,6 +81,21 @@
 	once.Get(key)
 }
 
+func TestOncePer_Get_wait(t *testing.T) {
+	once := OncePer{}
+	key := NewOnceKey("key")
+
+	ch := make(chan bool)
+
+	go once.Once(key, func() interface{} { close(ch); time.Sleep(100 * time.Millisecond); return "foo" })
+	<-ch
+	a := once.Get(key).(string)
+
+	if a != "foo" {
+		t.Errorf("expect %q, got %q", "foo", a)
+	}
+}
+
 func TestOncePer_OnceStringSlice(t *testing.T) {
 	once := OncePer{}
 	key := NewOnceKey("key")
diff --git a/android/register.go b/android/register.go
index 19745fe..93c2870 100644
--- a/android/register.go
+++ b/android/register.go
@@ -58,6 +58,9 @@
 func SingletonFactoryAdaptor(factory SingletonFactory) blueprint.SingletonFactory {
 	return func() blueprint.Singleton {
 		singleton := factory()
+		if makevars, ok := singleton.(SingletonMakeVarsProvider); ok {
+			registerSingletonMakeVarsProvider(makevars)
+		}
 		return singletonAdaptor{singleton}
 	}
 }
diff --git a/android/util.go b/android/util.go
index 92ab845..8fc159d 100644
--- a/android/util.go
+++ b/android/util.go
@@ -20,6 +20,11 @@
 	"strings"
 )
 
+// CopyOf returns a new slice that has the same contents as s.
+func CopyOf(s []string) []string {
+	return append([]string(nil), s...)
+}
+
 func JoinWithPrefix(strs []string, prefix string) string {
 	if len(strs) == 0 {
 		return ""
diff --git a/android/util_test.go b/android/util_test.go
index 1c791b2..2e5eb07 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"fmt"
 	"reflect"
 	"testing"
 )
@@ -359,3 +360,47 @@
 		})
 	}
 }
+
+func ExampleCopyOf() {
+	a := []string{"1", "2", "3"}
+	b := CopyOf(a)
+	a[0] = "-1"
+	fmt.Printf("a = %q\n", a)
+	fmt.Printf("b = %q\n", b)
+
+	// Output:
+	// a = ["-1" "2" "3"]
+	// b = ["1" "2" "3"]
+}
+
+func ExampleCopyOf_append() {
+	a := make([]string, 1, 2)
+	a[0] = "foo"
+
+	fmt.Println("Without CopyOf:")
+	b := append(a, "bar")
+	c := append(a, "baz")
+	fmt.Printf("a = %q\n", a)
+	fmt.Printf("b = %q\n", b)
+	fmt.Printf("c = %q\n", c)
+
+	a = make([]string, 1, 2)
+	a[0] = "foo"
+
+	fmt.Println("With CopyOf:")
+	b = append(CopyOf(a), "bar")
+	c = append(CopyOf(a), "baz")
+	fmt.Printf("a = %q\n", a)
+	fmt.Printf("b = %q\n", b)
+	fmt.Printf("c = %q\n", c)
+
+	// Output:
+	// Without CopyOf:
+	// a = ["foo"]
+	// b = ["foo" "baz"]
+	// c = ["foo" "baz"]
+	// With CopyOf:
+	// a = ["foo"]
+	// b = ["foo" "bar"]
+	// c = ["foo" "baz"]
+}
diff --git a/apex/apex.go b/apex/apex.go
index 3b06a99..408415e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -379,6 +379,13 @@
 	outputFiles      map[apexPackaging]android.WritablePath
 	installDir       android.OutputPath
 
+	public_key_file   android.Path
+	private_key_file  android.Path
+	bundle_public_key bool
+
+	container_certificate_file android.Path
+	container_private_key_file android.Path
+
 	// list of files to be included in this apex
 	filesInfo []apexFile
 
@@ -635,10 +642,6 @@
 func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	filesInfo := []apexFile{}
 
-	var keyFile android.Path
-	var pubKeyFile android.Path
-	var certificate java.Certificate
-
 	if a.properties.Payload_type == nil || *a.properties.Payload_type == "image" {
 		a.apexTypes = imageApex
 	} else if *a.properties.Payload_type == "zip" {
@@ -704,20 +707,20 @@
 				}
 			case keyTag:
 				if key, ok := child.(*apexKey); ok {
-					keyFile = key.private_key_file
-					if !key.installable() && ctx.Config().Debuggable() {
-						// If the key is not installed, bundled it with the APEX.
-						// Note: this bundled key is valid only for non-production builds
-						// (eng/userdebug).
-						pubKeyFile = key.public_key_file
-					}
+					a.private_key_file = key.private_key_file
+					a.public_key_file = key.public_key_file
+					// If the key is not installed, bundled it with the APEX.
+					// Note: this bundled key is valid only for non-production builds
+					// (eng/userdebug).
+					a.bundle_public_key = !key.installable() && ctx.Config().Debuggable()
 					return false
 				} else {
 					ctx.PropertyErrorf("key", "%q is not an apex_key module", depName)
 				}
 			case certificateTag:
 				if dep, ok := child.(*java.AndroidAppCertificate); ok {
-					certificate = dep.Certificate
+					a.container_certificate_file = dep.Certificate.Pem
+					a.container_private_key_file = dep.Certificate.Key
 					return false
 				} else {
 					ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", depName)
@@ -741,7 +744,7 @@
 	})
 
 	a.flattened = ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
-	if keyFile == nil {
+	if a.private_key_file == nil {
 		ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key))
 		return
 	}
@@ -775,30 +778,28 @@
 	a.filesInfo = filesInfo
 
 	if a.apexTypes.zip() {
-		a.buildUnflattenedApex(ctx, keyFile, pubKeyFile, certificate, zipApex)
+		a.buildUnflattenedApex(ctx, zipApex)
 	}
 	if a.apexTypes.image() {
 		// Build rule for unflattened APEX is created even when ctx.Config().FlattenApex()
 		// is true. This is to support referencing APEX via ":<module_name" syntax
 		// in other modules. It is in AndroidMk where the selection of flattened
 		// or unflattened APEX is made.
-		a.buildUnflattenedApex(ctx, keyFile, pubKeyFile, certificate, imageApex)
+		a.buildUnflattenedApex(ctx, imageApex)
 		a.buildFlattenedApex(ctx)
 	}
 }
 
-func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, keyFile android.Path,
-	pubKeyFile android.Path, certificate java.Certificate, apexType apexPackaging) {
+func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext, apexType apexPackaging) {
 	cert := String(a.properties.Certificate)
 	if cert != "" && android.SrcIsModule(cert) == "" {
 		defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
-		certificate = java.Certificate{
-			defaultDir.Join(ctx, cert+".x509.pem"),
-			defaultDir.Join(ctx, cert+".pk8"),
-		}
+		a.container_certificate_file = defaultDir.Join(ctx, cert+".x509.pem")
+		a.container_private_key_file = defaultDir.Join(ctx, cert+".pk8")
 	} else if cert == "" {
 		pem, key := ctx.Config().DefaultAppCertificate(ctx)
-		certificate = java.Certificate{pem, key}
+		a.container_certificate_file = pem
+		a.container_private_key_file = key
 	}
 
 	manifest := ctx.ExpandSource(proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"), "manifest")
@@ -886,10 +887,10 @@
 		optFlags := []string{}
 
 		// Additional implicit inputs.
-		implicitInputs = append(implicitInputs, cannedFsConfig, fileContexts, keyFile)
-		if pubKeyFile != nil {
-			implicitInputs = append(implicitInputs, pubKeyFile)
-			optFlags = append(optFlags, "--pubkey "+pubKeyFile.String())
+		implicitInputs = append(implicitInputs, cannedFsConfig, fileContexts, a.private_key_file)
+		if a.bundle_public_key {
+			implicitInputs = append(implicitInputs, a.public_key_file)
+			optFlags = append(optFlags, "--pubkey "+a.public_key_file.String())
 		}
 
 		manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
@@ -915,7 +916,7 @@
 				"manifest":         manifest.String(),
 				"file_contexts":    fileContexts.String(),
 				"canned_fs_config": cannedFsConfig.String(),
-				"key":              keyFile.String(),
+				"key":              a.private_key_file.String(),
 				"opt_flags":        strings.Join(optFlags, " "),
 			},
 		})
@@ -962,14 +963,14 @@
 		Output:      a.outputFiles[apexType],
 		Input:       unsignedOutputFile,
 		Args: map[string]string{
-			"certificates": strings.Join([]string{certificate.Pem.String(), certificate.Key.String()}, " "),
+			"certificates": a.container_certificate_file.String() + " " + a.container_private_key_file.String(),
 			"flags":        "-a 4096", //alignment
 		},
 	})
 
 	// Install to $OUT/soong/{target,host}/.../apex
 	if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) {
-		ctx.InstallFile(android.PathForModuleInstall(ctx, "apex"), ctx.ModuleName()+suffix, a.outputFiles[apexType])
+		ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFiles[apexType])
 	}
 }
 
diff --git a/apex/key.go b/apex/key.go
index 5282416..4c83861 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"io"
+	"strings"
 
 	"android/soong/android"
 
@@ -27,6 +28,8 @@
 
 func init() {
 	android.RegisterModuleType("apex_key", apexKeyFactory)
+	android.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
+	android.RegisterMakeVarsProvider(pctx, apexKeysFileProvider)
 }
 
 type apexKey struct {
@@ -102,3 +105,53 @@
 		},
 	}
 }
+
+////////////////////////////////////////////////////////////////////////
+// apex_keys_text
+type apexKeysText struct{}
+
+func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) {
+	output := android.PathForOutput(ctx, "apexkeys.txt")
+	*apexKeysFile(ctx.Config()) = output.String()
+	var filecontent strings.Builder
+	ctx.VisitAllModules(func(module android.Module) {
+		if m, ok := module.(android.Module); ok && !m.Enabled() {
+			return
+		}
+
+		if m, ok := module.(*apexBundle); ok {
+			fmt.Fprintf(&filecontent,
+				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q\\n",
+				m.Name()+".apex",
+				m.public_key_file.String(),
+				m.private_key_file.String(),
+				m.container_certificate_file.String(),
+				m.container_private_key_file.String())
+		}
+	})
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        android.WriteFile,
+		Description: "apex_keys.txt",
+		Output:      output,
+		Args: map[string]string{
+			"content": filecontent.String(),
+		},
+	})
+}
+
+var apexKeysFileKey = android.NewOnceKey("apexKeysFile")
+
+func apexKeysFile(config android.Config) *string {
+	return config.Once(apexKeysFileKey, func() interface{} {
+		str := ""
+		return &str
+	}).(*string)
+}
+
+func apexKeysTextFactory() android.Singleton {
+	return &apexKeysText{}
+}
+
+func apexKeysFileProvider(ctx android.MakeVarsContext) {
+	ctx.Strict("SOONG_APEX_KEYS_FILE", *apexKeysFile(ctx.Config()))
+}
diff --git a/cc/coverage.go b/cc/coverage.go
index 0549705..ad2f1e4 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -53,6 +53,10 @@
 		flags.Coverage = true
 		flags.GlobalFlags = append(flags.GlobalFlags, "--coverage", "-O0")
 		cov.linkCoverage = true
+
+		// Override -Wframe-larger-than and non-default optimization
+		// flags that the module may use.
+		flags.CFlags = append(flags.CFlags, "-Wno-frame-larger-than=", "-O0")
 	}
 
 	// Even if we don't have coverage enabled, if any of our object files were compiled
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 1f6002e..41c7d46 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -75,8 +75,7 @@
 	bootstrap.Main(ctx.Context, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
 
 	if docFile != "" {
-		err := writeDocs(ctx, docFile)
-		if err != nil {
+		if err := writeDocs(ctx, docFile); err != nil {
 			fmt.Fprintf(os.Stderr, "%s", err)
 			os.Exit(1)
 		}
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index 8f86b33..74c854a 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -26,7 +26,25 @@
 	"github.com/google/blueprint/bootstrap/bpdoc"
 )
 
-func writeDocs(ctx *android.Context, filename string) error {
+type moduleTypeTemplateData struct {
+	Name       string
+	Synopsis   string
+	Properties []bpdoc.Property
+}
+
+// The properties in this map are displayed first, according to their rank.
+// TODO(jungjw): consider providing module type-dependent ranking
+var propertyRank = map[string]int{
+	"name":             0,
+	"src":              1,
+	"srcs":             2,
+	"defautls":         3,
+	"host_supported":   4,
+	"device_supported": 5,
+}
+
+// For each module type, extract its documentation and convert it to the template data.
+func moduleTypeDocsToTemplates(ctx *android.Context) ([]moduleTypeTemplateData, error) {
 	moduleTypeFactories := android.ModuleTypeFactories()
 	bpModuleTypeFactories := make(map[string]reflect.Value)
 	for moduleType, factory := range moduleTypeFactories {
@@ -35,39 +53,83 @@
 
 	packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
 	if err != nil {
-		return err
+		return []moduleTypeTemplateData{}, err
 	}
-
-	buf := &bytes.Buffer{}
-
 	var moduleTypeList []*bpdoc.ModuleType
 	for _, pkg := range packages {
 		moduleTypeList = append(moduleTypeList, pkg.ModuleTypes...)
 	}
-	sort.Slice(moduleTypeList, func(i, j int) bool { return moduleTypeList[i].Name < moduleTypeList[j].Name })
 
-	unique := 0
+	result := make([]moduleTypeTemplateData, 0)
 
+	// Combine properties from all PropertyStruct's and reorder them -- first the ones
+	// with rank, then the rest of the properties in alphabetic order.
+	for _, m := range moduleTypeList {
+		item := moduleTypeTemplateData{
+			Name:       m.Name,
+			Synopsis:   m.Text,
+			Properties: make([]bpdoc.Property, 0),
+		}
+		props := make([]bpdoc.Property, 0)
+		for _, propStruct := range m.PropertyStructs {
+			props = append(props, propStruct.Properties...)
+		}
+		sort.Slice(props, func(i, j int) bool {
+			if rankI, ok := propertyRank[props[i].Name]; ok {
+				if rankJ, ok := propertyRank[props[j].Name]; ok {
+					return rankI < rankJ
+				} else {
+					return true
+				}
+			}
+			if _, ok := propertyRank[props[j].Name]; ok {
+				return false
+			}
+			return props[i].Name < props[j].Name
+		})
+		// Eliminate top-level duplicates. TODO(jungjw): improve bpdoc to handle this.
+		previousPropertyName := ""
+		for _, prop := range props {
+			if prop.Name == previousPropertyName {
+				oldProp := &item.Properties[len(item.Properties)-1].Properties
+				bpdoc.CollapseDuplicateProperties(oldProp, &prop.Properties)
+			} else {
+				item.Properties = append(item.Properties, prop)
+			}
+			previousPropertyName = prop.Name
+		}
+		result = append(result, item)
+	}
+	sort.Slice(result, func(i, j int) bool { return result[i].Name < result[j].Name })
+	return result, err
+}
+
+func writeDocs(ctx *android.Context, filename string) error {
+	buf := &bytes.Buffer{}
+
+	// We need a module name getter/setter function because I couldn't
+	// find a way to keep it in a variable defined within the template.
+	currentModuleName := ""
+	data, err := moduleTypeDocsToTemplates(ctx)
+	if err != nil {
+		return err
+	}
 	tmpl, err := template.New("file").Funcs(map[string]interface{}{
-		"unique": func() int {
-			unique++
-			return unique
-		}}).Parse(fileTemplate)
-	if err != nil {
-		return err
+		"setModule": func(moduleName string) string {
+			currentModuleName = moduleName
+			return ""
+		},
+		"getModule": func() string {
+			return currentModuleName
+		},
+	}).Parse(fileTemplate)
+	if err == nil {
+		err = tmpl.Execute(buf, data)
 	}
-
-	err = tmpl.Execute(buf, moduleTypeList)
-	if err != nil {
-		return err
+	if err == nil {
+		err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
 	}
-
-	err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
-	if err != nil {
-		return err
-	}
-
-	return nil
+	return err
 }
 
 const (
@@ -75,70 +137,112 @@
 <html>
 <head>
 <title>Build Docs</title>
-<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
-<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
-<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
+<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css">
+<style>
+.accordion,.simple{margin-left:1.5em;text-indent:-1.5em;margin-top:.25em}
+.collapsible{border-width:0 0 0 1;margin-left:.25em;padding-left:.25em;border-style:solid;
+  border-color:grey;display:none;}
+span.fixed{display: block; float: left; clear: left; width: 1em;}
+ul {
+	list-style-type: none;
+  margin: 0;
+  padding: 0;
+  width: 30ch;
+  background-color: #f1f1f1;
+  position: fixed;
+  height: 100%;
+  overflow: auto;
+}
+li a {
+  display: block;
+  color: #000;
+  padding: 8px 16px;
+  text-decoration: none;
+}
+
+li a.active {
+  background-color: #4CAF50;
+  color: white;
+}
+
+li a:hover:not(.active) {
+  background-color: #555;
+  color: white;
+}
+</style>
 </head>
 <body>
-<h1>Build Docs</h1>
-<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
-  {{range .}}
-    {{ $collapseIndex := unique }}
-    <div class="panel panel-default">
-      <div class="panel-heading" role="tab" id="heading{{$collapseIndex}}">
-        <h2 class="panel-title">
-          <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse{{$collapseIndex}}" aria-expanded="false" aria-controls="collapse{{$collapseIndex}}">
-             {{.Name}}
-          </a>
-        </h2>
-      </div>
-    </div>
-    <div id="collapse{{$collapseIndex}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading{{$collapseIndex}}">
-      <div class="panel-body">
-        <p>{{.Text}}</p>
-        {{range .PropertyStructs}}
-          <p>{{.Text}}</p>
-          {{template "properties" .Properties}}
-        {{end}}
-      </div>
-    </div>
-  {{end}}
-</div>
-</body>
-</html>
+{{- /* Fixed sidebar with module types */ -}}
+<ul>
+<li><h3>Module Types:</h3></li>
+{{range $moduleType := .}}<li><a href="#{{$moduleType.Name}}">{{$moduleType.Name}}</a></li>
+{{end -}}
+</ul>
+{{/* Main panel with H1 section per module type */}}
+<div style="margin-left:30ch;padding:1px 16px;">
+<H1>Soong Modules Reference</H1>
+The latest versions of Android use the Soong build system, which greatly simplifies build
+configuration over the previous Make-based system. This site contains the generated reference
+files for the Soong build system.
+<p>
+See the <a href=https://source.android.com/setup/build/build-system>Android Build System</a>
+description for an overview of Soong and examples for its use.
 
-{{define "properties"}}
-  <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
-    {{range .}}
-      {{$collapseIndex := unique}}
-      {{if .Properties}}
-        <div class="panel panel-default">
-          <div class="panel-heading" role="tab" id="heading{{$collapseIndex}}">
-            <h4 class="panel-title">
-              <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse{{$collapseIndex}}" aria-expanded="false" aria-controls="collapse{{$collapseIndex}}">
-                 {{.Name}}{{range .OtherNames}}, {{.}}{{end}}
-              </a>
-            </h4>
-          </div>
-        </div>
-        <div id="collapse{{$collapseIndex}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading{{$collapseIndex}}">
-          <div class="panel-body">
-            <p>{{.Text}}</p>
-            {{range .OtherTexts}}<p>{{.}}</p>{{end}}
-            {{template "properties" .Properties}}
-          </div>
-        </div>
-      {{else}}
-        <div>
-          <h4>{{.Name}}{{range .OtherNames}}, {{.}}{{end}}</h4>
-          <p>{{.Text}}</p>
-          {{range .OtherTexts}}<p>{{.}}</p>{{end}}
-          <p><i>Type: {{.Type}}</i></p>
-          {{if .Default}}<p><i>Default: {{.Default}}</i></p>{{end}}
-        </div>
-      {{end}}
-    {{end}}
+{{range $imodule, $moduleType := .}}
+	{{setModule $moduleType.Name}}
+	<p>
+  <h2 id="{{$moduleType.Name}}">{{$moduleType.Name}}</h2>
+  {{if $moduleType.Synopsis }}{{$moduleType.Synopsis}}{{else}}<i>Missing synopsis</i>{{end}}
+  {{- /* Comma-separated list of module attributes' links module attributes */ -}}
+	<div class="breadcrumb">
+    {{range $i,$prop := $moduleType.Properties }}
+				{{ if gt $i 0 }},&nbsp;{{end -}}
+				<a href=#{{getModule}}.{{$prop.Name}}>{{$prop.Name}}</a>
+		{{- end -}}
   </div>
-{{end}}
+	{{- /* Property description */ -}}
+	{{- template "properties" $moduleType.Properties -}}
+{{- end -}}
+
+{{define "properties" -}}
+  {{range .}}
+    {{if .Properties -}}
+      <div class="accordion"  id="{{getModule}}.{{.Name}}">
+        <span class="fixed">&#x2295</span><b>{{.Name}}</b>
+        {{- range .OtherNames -}}, {{.}}{{- end -}}
+      </div>
+      <div class="collapsible">
+        {{- .Text}} {{range .OtherTexts}}{{.}}{{end}}
+        {{template "properties" .Properties -}}
+      </div>
+    {{- else -}}
+      <div class="simple" id="{{getModule}}.{{.Name}}">
+        <span class="fixed">&nbsp;</span><b>{{.Name}} {{range .OtherNames}}, {{.}}{{end -}}</b>
+        {{- if .Text -}}{{.Text}}{{- end -}}
+        {{- with .OtherTexts -}}{{.}}{{- end -}}<i>{{.Type}}</i>
+	{{- if .Default -}}<i>Default: {{.Default}}</i>{{- end -}}
+      </div>
+    {{- end}}
+  {{- end -}}
+{{- end -}}
+
+</div>
+<script>
+  accordions = document.getElementsByClassName('accordion');
+  for (i=0; i < accordions.length; ++i) {
+    accordions[i].addEventListener("click", function() {
+      var panel = this.nextElementSibling;
+      var child = this.firstElementChild;
+      if (panel.style.display === "block") {
+          panel.style.display = "none";
+          child.textContent = '\u2295';
+      } else {
+          panel.style.display = "block";
+          child.textContent = '\u2296';
+      }
+    });
+  }
+</script>
+</body>
 `
 )
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index eacb86a..7fdfb49 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -578,9 +578,7 @@
 	}
 }
 
-func copyOf(l []string) []string {
-	return append([]string(nil), l...)
-}
+var copyOf = android.CopyOf
 
 func anyHavePrefix(l []string, prefix string) bool {
 	for _, x := range l {
diff --git a/java/aar.go b/java/aar.go
index b8a5e35..e5ab036 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -190,9 +190,6 @@
 	linkFlags, linkDeps, resDirs, overlayDirs, rroDirs := a.aapt2Flags(ctx, sdkContext, manifestPath)
 
 	rroDirs = append(rroDirs, staticRRODirs...)
-	// TODO(b/124035856): stop de-duping when there are no more dupe resource dirs.
-	rroDirs = android.FirstUniquePaths(rroDirs)
-
 	linkFlags = append(linkFlags, libFlags...)
 	linkDeps = append(linkDeps, libDeps...)
 	linkFlags = append(linkFlags, extraLinkFlags...)
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index de1bcf5..adbd356 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -44,13 +44,15 @@
 }
 
 func hiddenAPISingletonFactory() android.Singleton {
-	return hiddenAPISingleton{}
+	return &hiddenAPISingleton{}
 }
 
-type hiddenAPISingleton struct{}
+type hiddenAPISingleton struct {
+	flags, metadata android.Path
+}
 
 // hiddenAPI singleton rules
-func (hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) {
+func (h *hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) {
 	// Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
 	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
 		return
@@ -60,10 +62,24 @@
 
 	// These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them.
 	if ctx.Config().FrameworksBaseDirExists(ctx) {
-		flagsRule(ctx)
-		metadataRule(ctx)
+		h.flags = flagsRule(ctx)
+		h.metadata = metadataRule(ctx)
 	} else {
-		emptyFlagsRule(ctx)
+		h.flags = emptyFlagsRule(ctx)
+	}
+}
+
+// Export paths to Make.  INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
+// Both paths are used to call dist-for-goals.
+func (h *hiddenAPISingleton) MakeVars(ctx android.MakeVarsContext) {
+	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+		return
+	}
+
+	ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", h.flags.String())
+
+	if h.metadata != nil {
+		ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", h.metadata.String())
 	}
 }
 
@@ -170,7 +186,7 @@
 
 // flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
 // the greylists.
-func flagsRule(ctx android.SingletonContext) {
+func flagsRule(ctx android.SingletonContext) android.Path {
 	var flagsCSV android.Paths
 
 	var greylistIgnoreConflicts android.Path
@@ -187,7 +203,7 @@
 
 	if greylistIgnoreConflicts == nil {
 		ctx.Errorf("failed to find removed_dex_api_filename from hiddenapi-lists-docs module")
-		return
+		return nil
 	}
 
 	rule := android.NewRuleBuilder()
@@ -216,11 +232,13 @@
 	commitChangeForRestat(rule, tempPath, outputPath)
 
 	rule.Build(pctx, ctx, "hiddenAPIFlagsFile", "hiddenapi flags")
+
+	return outputPath
 }
 
 // emptyFlagsRule creates a rule to build an empty hiddenapi-flags.csv, which is needed by master-art-host builds that
 // have a partial manifest without frameworks/base but still need to build a boot image.
-func emptyFlagsRule(ctx android.SingletonContext) {
+func emptyFlagsRule(ctx android.SingletonContext) android.Path {
 	rule := android.NewRuleBuilder()
 
 	outputPath := hiddenAPISingletonPaths(ctx).flags
@@ -229,11 +247,13 @@
 	rule.Command().Text("touch").Output(outputPath.String())
 
 	rule.Build(pctx, ctx, "emptyHiddenAPIFlagsFile", "empty hiddenapi flags")
+
+	return outputPath
 }
 
 // metadataRule creates a rule to build hiddenapi-greylist.csv out of the metadata.csv files generated for boot image
 // modules.
-func metadataRule(ctx android.SingletonContext) {
+func metadataRule(ctx android.SingletonContext) android.Path {
 	var metadataCSV android.Paths
 
 	ctx.VisitAllModules(func(module android.Module) {
@@ -255,6 +275,8 @@
 		Output(outputPath.String())
 
 	rule.Build(pctx, ctx, "hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata")
+
+	return outputPath
 }
 
 // commitChangeForRestat adds a command to a rule that updates outputPath from tempPath if they are different.  It
@@ -274,17 +296,3 @@
 		Text("fi").
 		Text(")")
 }
-
-func init() {
-	android.RegisterMakeVarsProvider(pctx, hiddenAPIMakeVars)
-}
-
-// Export paths to Make.  INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
-// Both paths are used to call dist-for-goals.
-func hiddenAPIMakeVars(ctx android.MakeVarsContext) {
-	if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
-		singletonPaths := hiddenAPISingletonPaths(ctx)
-		ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", singletonPaths.flags.String())
-		ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", singletonPaths.metadata.String())
-	}
-}
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index d4922f3..fb30f85 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,41 +74,39 @@
 }
 
 var Configuration = map[string]PathConfig{
-	"bash":      Allowed,
-	"bc":        Allowed,
-	"bzip2":     Allowed,
-	"date":      Allowed,
-	"dd":        Allowed,
-	"diff":      Allowed,
-	"egrep":     Allowed,
-	"find":      Allowed,
-	"fuser":     Allowed,
-	"getopt":    Allowed,
-	"git":       Allowed,
-	"grep":      Allowed,
-	"gzip":      Allowed,
-	"hexdump":   Allowed,
-	"jar":       Allowed,
-	"java":      Allowed,
-	"javap":     Allowed,
-	"lsof":      Allowed,
-	"m4":        Allowed,
-	"openssl":   Allowed,
-	"patch":     Allowed,
-	"pstree":    Allowed,
-	"python":    Allowed,
-	"python2.7": Allowed,
-	"python3":   Allowed,
-	"realpath":  Allowed,
-	"rsync":     Allowed,
-	"sh":        Allowed,
-	"tar":       Allowed,
-	"timeout":   Allowed,
-	"tr":        Allowed,
-	"unzip":     Allowed,
-	"xz":        Allowed,
-	"zip":       Allowed,
-	"zipinfo":   Allowed,
+	"bash":     Allowed,
+	"bc":       Allowed,
+	"bzip2":    Allowed,
+	"date":     Allowed,
+	"dd":       Allowed,
+	"diff":     Allowed,
+	"egrep":    Allowed,
+	"find":     Allowed,
+	"fuser":    Allowed,
+	"getopt":   Allowed,
+	"git":      Allowed,
+	"grep":     Allowed,
+	"gzip":     Allowed,
+	"hexdump":  Allowed,
+	"jar":      Allowed,
+	"java":     Allowed,
+	"javap":    Allowed,
+	"lsof":     Allowed,
+	"m4":       Allowed,
+	"openssl":  Allowed,
+	"patch":    Allowed,
+	"pstree":   Allowed,
+	"python3":  Allowed,
+	"realpath": Allowed,
+	"rsync":    Allowed,
+	"sh":       Allowed,
+	"tar":      Allowed,
+	"timeout":  Allowed,
+	"tr":       Allowed,
+	"unzip":    Allowed,
+	"xz":       Allowed,
+	"zip":      Allowed,
+	"zipinfo":  Allowed,
 
 	// Host toolchain is removed. In-tree toolchain should be used instead.
 	// GCC also can't find cc1 with this implementation.