Merge "cc_prebuilt_library respect module name and stem"
diff --git a/android/api_levels.go b/android/api_levels.go
index 4f6efee..4b7a8fd 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -73,7 +73,7 @@
 			"P":     28,
 			"Q":     29,
 		}
-		for i, codename := range config.PlatformVersionCombinedCodenames() {
+		for i, codename := range config.PlatformVersionActiveCodenames() {
 			apiLevelsMap[codename] = baseApiLevel + i
 		}
 
diff --git a/android/config.go b/android/config.go
index 558c828..c297b05 100644
--- a/android/config.go
+++ b/android/config.go
@@ -652,22 +652,6 @@
 	return c.productVariables.Platform_version_active_codenames
 }
 
-// Codenames that are available in the branch but not included in the current
-// lunch target.
-func (c *config) PlatformVersionFutureCodenames() []string {
-	return c.productVariables.Platform_version_future_codenames
-}
-
-// All possible codenames in the current branch. NB: Not named AllCodenames
-// because "all" has historically meant "active" in make, and still does in
-// build.prop.
-func (c *config) PlatformVersionCombinedCodenames() []string {
-	combined := []string{}
-	combined = append(combined, c.PlatformVersionActiveCodenames()...)
-	combined = append(combined, c.PlatformVersionFutureCodenames()...)
-	return combined
-}
-
 func (c *config) ProductAAPTConfig() []string {
 	return c.productVariables.AAPTConfig
 }
diff --git a/android/mutator.go b/android/mutator.go
index a46d4be..10a815a 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -103,7 +103,7 @@
 	registerPathDepsMutator,
 	RegisterPrebuiltsPostDepsMutators,
 	RegisterVisibilityRuleEnforcer,
-	registerNeverallowMutator,
+	RegisterNeverallowMutator,
 	RegisterOverridePostDepsMutators,
 }
 
diff --git a/android/neverallow.go b/android/neverallow.go
index 04ec27d..cf09792 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -42,7 +42,7 @@
 //     counts as a match
 // - it has none of the "Without" properties matched (same rules as above)
 
-func registerNeverallowMutator(ctx RegisterMutatorsContext) {
+func RegisterNeverallowMutator(ctx RegisterMutatorsContext) {
 	ctx.BottomUp("neverallow", neverallowMutator).Parallel()
 }
 
@@ -247,7 +247,7 @@
 }
 
 type ValueMatcher interface {
-	test(string) bool
+	Test(string) bool
 	String() string
 }
 
@@ -255,7 +255,7 @@
 	expected string
 }
 
-func (m *equalMatcher) test(value string) bool {
+func (m *equalMatcher) Test(value string) bool {
 	return m.expected == value
 }
 
@@ -266,7 +266,7 @@
 type anyMatcher struct {
 }
 
-func (m *anyMatcher) test(value string) bool {
+func (m *anyMatcher) Test(value string) bool {
 	return true
 }
 
@@ -280,7 +280,7 @@
 	prefix string
 }
 
-func (m *startsWithMatcher) test(value string) bool {
+func (m *startsWithMatcher) Test(value string) bool {
 	return strings.HasPrefix(value, m.prefix)
 }
 
@@ -292,7 +292,7 @@
 	re *regexp.Regexp
 }
 
-func (m *regexMatcher) test(value string) bool {
+func (m *regexMatcher) Test(value string) bool {
 	return m.re.MatchString(value)
 }
 
@@ -302,7 +302,7 @@
 
 type isSetMatcher struct{}
 
-func (m *isSetMatcher) test(value string) bool {
+func (m *isSetMatcher) Test(value string) bool {
 	return value != ""
 }
 
@@ -573,7 +573,7 @@
 		}
 
 		check := func(value string) bool {
-			return prop.matcher.test(value)
+			return prop.matcher.Test(value)
 		}
 
 		if matchValue(propertiesValue, check) {
@@ -630,6 +630,6 @@
 // Overrides the default neverallow rules for the supplied config.
 //
 // For testing only.
-func setTestNeverallowRules(config Config, testRules []Rule) {
+func SetTestNeverallowRules(config Config, testRules []Rule) {
 	config.Once(neverallowRulesKey, func() interface{} { return testRules })
 }
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 0373b79..2fc42e3 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -313,7 +313,7 @@
 		t.Run(test.name, func(t *testing.T) {
 			// If the test has its own rules then use them instead of the default ones.
 			if test.rules != nil {
-				setTestNeverallowRules(config, test.rules)
+				SetTestNeverallowRules(config, test.rules)
 			}
 			_, errs := testNeverallow(config)
 			CheckErrorsAgainstExpectations(t, errs, test.expectedErrors)
@@ -327,7 +327,7 @@
 	ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
 	ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
 	ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
-	ctx.PostDepsMutators(registerNeverallowMutator)
+	ctx.PostDepsMutators(RegisterNeverallowMutator)
 	ctx.Register(config)
 
 	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
diff --git a/android/variable.go b/android/variable.go
index 612d138..3b3916e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -151,7 +151,6 @@
 	Platform_sdk_codename                     *string  `json:",omitempty"`
 	Platform_sdk_final                        *bool    `json:",omitempty"`
 	Platform_version_active_codenames         []string `json:",omitempty"`
-	Platform_version_future_codenames         []string `json:",omitempty"`
 	Platform_vndk_version                     *string  `json:",omitempty"`
 	Platform_systemsdk_versions               []string `json:",omitempty"`
 	Platform_security_patch                   *string  `json:",omitempty"`
@@ -255,7 +254,7 @@
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
 
-	SamplingPGO  *bool   `json:",omitempty"`
+	SamplingPGO *bool `json:",omitempty"`
 
 	NativeLineCoverage   *bool    `json:",omitempty"`
 	Native_coverage      *bool    `json:",omitempty"`
@@ -358,7 +357,6 @@
 		Platform_sdk_codename:             stringPtr("Q"),
 		Platform_sdk_final:                boolPtr(false),
 		Platform_version_active_codenames: []string{"Q"},
-		Platform_version_future_codenames: []string{"Q"},
 		Platform_vndk_version:             stringPtr("Q"),
 
 		HostArch:                   stringPtr("x86_64"),
diff --git a/apex/vndk.go b/apex/vndk.go
index 2a0d5b0..f948d76 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -16,6 +16,7 @@
 
 import (
 	"path/filepath"
+	"strconv"
 	"strings"
 	"sync"
 
@@ -121,10 +122,13 @@
 	// When all hard-coded references are fixed, remove symbolic links
 	// Note that  we should keep following symlinks for older VNDKs (<=29)
 	// Since prebuilt vndk libs still depend on system/lib/vndk path
-	if strings.HasPrefix(name, vndkApexName) {
-		vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
-		if strings.HasPrefix(name, vndkApexNamePrefix) {
-			vndkVersion = strings.TrimPrefix(name, vndkApexNamePrefix)
+	if strings.HasPrefix(name, vndkApexNamePrefix) {
+		vndkVersion := strings.TrimPrefix(name, vndkApexNamePrefix)
+		if numVer, err := strconv.Atoi(vndkVersion); err != nil {
+			ctx.ModuleErrorf("apex_vndk should be named as %v<ver:number>: %s", vndkApexNamePrefix, name)
+			return
+		} else if numVer > android.SdkVersion_Android10 {
+			return
 		}
 		// the name of vndk apex is formatted "com.android.vndk.v" + version
 		apexName := vndkApexNamePrefix + vndkVersion
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 19c7182..5438b14 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -271,6 +271,10 @@
 			entries.SubName = "." + library.stubsVersion()
 		}
 		entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+			// Note library.skipInstall() has a special case to get here for static
+			// libraries that otherwise would have skipped installation and hence not
+			// have executed AndroidMkEntries at all. The reason is to ensure they get
+			// a NOTICE file make target which other libraries might depend on.
 			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 			if library.buildStubs() {
 				entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
diff --git a/cc/cc.go b/cc/cc.go
index 4667a3d..0201404 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -404,6 +404,7 @@
 	inSanitizerDir() bool
 	hostToolPath() android.OptionalPath
 	relativeInstallPath() string
+	skipInstall(mod *Module)
 }
 
 type xref interface {
@@ -1118,7 +1119,7 @@
 	if ctx.ctx.Device() {
 		if ctx.useVndk() {
 			vndkVer := ctx.mod.VndkVersion()
-			if inList(vndkVer, ctx.ctx.Config().PlatformVersionCombinedCodenames()) {
+			if inList(vndkVer, ctx.ctx.Config().PlatformVersionActiveCodenames()) {
 				return "current"
 			}
 			return vndkVer
@@ -2639,6 +2640,14 @@
 	return c.InRecovery()
 }
 
+func (c *Module) SkipInstall() {
+	if c.installer == nil {
+		c.ModuleBase.SkipInstall()
+		return
+	}
+	c.installer.skipInstall(c)
+}
+
 func (c *Module) HostToolPath() android.OptionalPath {
 	if c.installer == nil {
 		return android.OptionalPath{}
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 19aedd9..5575baa 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -37,10 +37,8 @@
 	}
 
 	arm64Ldflags = []string{
-		"-Wl,-m,aarch64_elf64_le_vec",
 		"-Wl,--hash-style=gnu",
 		"-Wl,-z,separate-code",
-		"-fuse-ld=gold",
 		"-Wl,--icf=safe",
 	}
 
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 274ccd5..bdd9030 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -80,10 +80,8 @@
 
 // Ldflags that should be filtered out when linking with clang lld
 var ClangUnknownLldflags = sorted([]string{
-	"-fuse-ld=gold",
 	"-Wl,--fix-cortex-a8",
 	"-Wl,--no-fix-cortex-a8",
-	"-Wl,-m,aarch64_elf64_le_vec",
 })
 
 var ClangLibToolingUnknownCflags = sorted([]string{})
diff --git a/cc/installer.go b/cc/installer.go
index 200d59e..0b4a68c 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -106,3 +106,7 @@
 func (installer *baseInstaller) relativeInstallPath() string {
 	return String(installer.Properties.Relative_install_path)
 }
+
+func (installer *baseInstaller) skipInstall(mod *Module) {
+	mod.ModuleBase.SkipInstall()
+}
diff --git a/cc/library.go b/cc/library.go
index 140f87a..94fffb9 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1329,6 +1329,18 @@
 	return android.CheckAvailableForApex(what, list)
 }
 
+func (library *libraryDecorator) skipInstall(mod *Module) {
+	if library.static() && library.buildStatic() && !library.buildStubs() {
+		// If we're asked to skip installation of a static library (in particular
+		// when it's not //apex_available:platform) we still want an AndroidMk entry
+		// for it to ensure we get the relevant NOTICE file targets (cf.
+		// notice_files.mk) that other libraries might depend on. AndroidMkEntries
+		// always sets LOCAL_UNINSTALLABLE_MODULE for these entries.
+		return
+	}
+	mod.ModuleBase.SkipInstall()
+}
+
 var versioningMacroNamesListKey = android.NewOnceKey("versioningMacroNamesList")
 
 func versioningMacroNamesList(config android.Config) *map[string]string {
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 09050aa..7ff20f4 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -83,7 +83,7 @@
 
 func (stub *llndkStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	vndkVer := ctx.Module().(*Module).VndkVersion()
-	if !inList(vndkVer, ctx.Config().PlatformVersionCombinedCodenames()) || vndkVer == "" {
+	if !inList(vndkVer, ctx.Config().PlatformVersionActiveCodenames()) || vndkVer == "" {
 		// For non-enforcing devices, vndkVer is empty. Use "current" in that case, too.
 		vndkVer = "current"
 	}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 35d95f7..ac990f3 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -198,6 +198,10 @@
 	p.properties.Srcs = nil
 }
 
+func (p *prebuiltLibraryLinker) skipInstall(mod *Module) {
+	mod.ModuleBase.SkipInstall()
+}
+
 func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
 	module, library := NewLibrary(hod)
 	module.compiler = nil
@@ -206,6 +210,7 @@
 		libraryDecorator: library,
 	}
 	module.linker = prebuilt
+	module.installer = prebuilt
 
 	module.AddProperties(&prebuilt.properties)
 
diff --git a/java/app.go b/java/app.go
index c9ae3e7..ac5121a 100755
--- a/java/app.go
+++ b/java/app.go
@@ -110,6 +110,10 @@
 	PreventInstall    bool `blueprint:"mutated"`
 	HideFromMake      bool `blueprint:"mutated"`
 	IsCoverageVariant bool `blueprint:"mutated"`
+
+	// Whether this app is considered mainline updatable or not. When set to true, this will enforce
+	// additional rules for making sure that the APK is truly updatable. Default is false.
+	Updatable *bool
 }
 
 // android_app properties that can be overridden by override_android_app
@@ -249,11 +253,21 @@
 }
 
 func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	a.checkPlatformAPI(ctx)
-	a.checkSdkVersion(ctx)
+	a.checkAppSdkVersions(ctx)
 	a.generateAndroidBuildActions(ctx)
 }
 
+func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
+	if Bool(a.appProperties.Updatable) {
+		if !a.sdkVersion().stable() {
+			ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.sdkVersion())
+		}
+	}
+
+	a.checkPlatformAPI(ctx)
+	a.checkSdkVersions(ctx)
+}
+
 // Returns true if the native libraries should be stored in the APK uncompressed and the
 // extractNativeLibs application flag should be set to false in the manifest.
 func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
@@ -1369,6 +1383,12 @@
 	// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
 	// Defaults to sdk_version if not set.
 	Min_sdk_version *string
+
+	// list of android_library modules whose resources are extracted and linked against statically
+	Static_libs []string
+
+	// list of android_app modules whose resources are extracted and linked against
+	Resource_libs []string
 }
 
 func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1381,6 +1401,9 @@
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
+
+	ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs...)
+	ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...)
 }
 
 func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
diff --git a/java/app_test.go b/java/app_test.go
index f2ec483..7b04e46 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -264,6 +264,108 @@
 	`)
 }
 
+func TestUpdatableApps(t *testing.T) {
+	testCases := []struct {
+		name          string
+		bp            string
+		expectedError string
+	}{
+		{
+			name: "Stable public SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "29",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Stable system SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "system_29",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Current public SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "current",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Current system SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "system_current",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Current module SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "module_current",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "Current core SDK",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "core_current",
+					updatable: true,
+				}`,
+		},
+		{
+			name: "No Platform APIs",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					platform_apis: true,
+					updatable: true,
+				}`,
+			expectedError: "Updatable apps must use stable SDKs",
+		},
+		{
+			name: "No Core Platform APIs",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					sdk_version: "core_platform",
+					updatable: true,
+				}`,
+			expectedError: "Updatable apps must use stable SDKs",
+		},
+		{
+			name: "No unspecified APIs",
+			bp: `android_app {
+					name: "foo",
+					srcs: ["a.java"],
+					updatable: true,
+				}`,
+			expectedError: "Updatable apps must use stable SDK",
+		},
+	}
+
+	for _, test := range testCases {
+		t.Run(test.name, func(t *testing.T) {
+			if test.expectedError == "" {
+				testJava(t, test.bp)
+			} else {
+				testJavaError(t, test.expectedError, test.bp)
+			}
+		})
+	}
+}
+
 func TestResourceDirs(t *testing.T) {
 	testCases := []struct {
 		name      string
@@ -2349,11 +2451,17 @@
 }
 
 func TestRuntimeResourceOverlay(t *testing.T) {
-	ctx, config := testJava(t, `
+	fs := map[string][]byte{
+		"baz/res/res/values/strings.xml": nil,
+		"bar/res/res/values/strings.xml": nil,
+	}
+	bp := `
 		runtime_resource_overlay {
 			name: "foo",
 			certificate: "platform",
 			product_specific: true,
+			static_libs: ["bar"],
+			resource_libs: ["baz"],
 			aaptflags: ["--keep-raw-values"],
 		}
 
@@ -2363,7 +2471,21 @@
 			product_specific: true,
 			theme: "faza",
 		}
-		`)
+
+		android_library {
+			name: "bar",
+			resource_dirs: ["bar/res"],
+		}
+
+		android_app {
+			name: "baz",
+			sdk_version: "current",
+			resource_dirs: ["baz/res"],
+		}
+		`
+	config := testAppConfig(nil, bp, fs)
+	ctx := testContext()
+	run(t, ctx, config)
 
 	m := ctx.ModuleForTests("foo", "android_common")
 
@@ -2375,6 +2497,19 @@
 		t.Errorf("expected values, %q are missing in aapt2 link flags, %q", absentFlags, aapt2Flags)
 	}
 
+	// Check overlay.list output for static_libs dependency.
+	overlayList := m.Output("aapt2/overlay.list").Inputs.Strings()
+	staticLibPackage := buildDir + "/.intermediates/bar/android_common/package-res.apk"
+	if !inList(staticLibPackage, overlayList) {
+		t.Errorf("Stactic lib res package %q missing in overlay list: %q", staticLibPackage, overlayList)
+	}
+
+	// Check AAPT2 link flags for resource_libs dependency.
+	resourceLibFlag := "-I " + buildDir + "/.intermediates/baz/android_common/package-res.apk"
+	if !strings.Contains(aapt2Flags, resourceLibFlag) {
+		t.Errorf("Resource lib flag %q missing in aapt2 link flags: %q", resourceLibFlag, aapt2Flags)
+	}
+
 	// Check cert signing flag.
 	signedApk := m.Output("signed/foo.apk")
 	signingFlag := signedApk.Args["certificates"]
diff --git a/java/java.go b/java/java.go
index a8ca3ff..61974f5 100644
--- a/java/java.go
+++ b/java/java.go
@@ -86,7 +86,7 @@
 	ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
 }
 
-func (j *Module) checkSdkVersion(ctx android.ModuleContext) {
+func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
 	if j.SocSpecific() || j.DeviceSpecific() ||
 		(j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
 		if sc, ok := ctx.Module().(sdkContext); ok {
@@ -96,6 +96,18 @@
 			}
 		}
 	}
+
+	ctx.VisitDirectDeps(func(module android.Module) {
+		tag := ctx.OtherModuleDependencyTag(module)
+		switch module.(type) {
+		// TODO(satayev): cover other types as well, e.g. imports
+		case *Library, *AndroidLibrary:
+			switch tag {
+			case bootClasspathTag, libTag, staticLibTag, java9LibTag:
+				checkLinkType(ctx, j, module.(linkTypeContext), tag.(dependencyTag))
+			}
+		}
+	})
 }
 
 func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
@@ -898,15 +910,7 @@
 			// Handled by AndroidApp.collectAppDeps
 			return
 		}
-		switch module.(type) {
-		case *Library, *AndroidLibrary:
-			if to, ok := module.(linkTypeContext); ok {
-				switch tag {
-				case bootClasspathTag, libTag, staticLibTag:
-					checkLinkType(ctx, j, to, tag.(dependencyTag))
-				}
-			}
-		}
+
 		switch dep := module.(type) {
 		case SdkLibraryDependency:
 			switch tag {
@@ -1818,7 +1822,7 @@
 }
 
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	j.checkSdkVersion(ctx)
+	j.checkSdkVersions(ctx)
 	j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
 	j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
 	j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
diff --git a/java/sdk.go b/java/sdk.go
index 0e132d3..92076f4 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -147,6 +147,10 @@
 	raw     string
 }
 
+func (s sdkSpec) String() string {
+	return fmt.Sprintf("%s_%s", s.kind, s.version)
+}
+
 // valid checks if this sdkSpec is well-formed. Note however that true doesn't mean that the
 // specified SDK actually exists.
 func (s sdkSpec) valid() bool {
@@ -158,6 +162,23 @@
 	return s.valid() && s.kind != sdkPrivate
 }
 
+// whether the API surface is managed and versioned, i.e. has .txt file that
+// get frozen on SDK freeze and changes get reviewed by API council.
+func (s sdkSpec) stable() bool {
+	if !s.specified() {
+		return false
+	}
+	switch s.kind {
+	case sdkCore, sdkPublic, sdkSystem, sdkModule, sdkSystemServer:
+		return true
+	case sdkNone, sdkCorePlatform, sdkTest, sdkPrivate:
+		return false
+	default:
+		panic(fmt.Errorf("unknown sdkKind=%v", s.kind))
+	}
+	return false
+}
+
 // prebuiltSdkAvailableForUnbundledBuilt tells whether this sdkSpec can have a prebuilt SDK
 // that can be used for unbundled builds.
 func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool {
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 60796d8..180fd8b 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -27,7 +27,6 @@
 		"-Wl,--icf=safe",
 		"-Wl,-z,max-page-size=4096",
 
-		"-Wl,--execute-only",
 		"-Wl,-z,separate-code",
 	}
 
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index 4c3bac3..98eb028 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -19,6 +19,7 @@
 	"os"
 	"os/exec"
 	"os/user"
+	"path/filepath"
 	"strings"
 	"sync"
 )
@@ -75,9 +76,20 @@
 			sandboxConfig.group = "nobody"
 		}
 
+		// These directories will be bind mounted
+		// so we need full non-symlink paths
 		sandboxConfig.srcDir = absPath(c.ctx, ".")
+		if derefPath, err := filepath.EvalSymlinks(sandboxConfig.srcDir); err == nil {
+			sandboxConfig.srcDir = absPath(c.ctx, derefPath)
+		}
 		sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir())
+		if derefPath, err := filepath.EvalSymlinks(sandboxConfig.outDir); err == nil {
+			sandboxConfig.outDir = absPath(c.ctx, derefPath)
+		}
 		sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir())
+		if derefPath, err := filepath.EvalSymlinks(sandboxConfig.distDir); err == nil {
+			sandboxConfig.distDir = absPath(c.ctx, derefPath)
+		}
 
 		sandboxArgs := []string{
 			"-H", "android-build",
diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp
index 529639d..3596e10 100644
--- a/ui/metrics/Android.bp
+++ b/ui/metrics/Android.bp
@@ -17,6 +17,7 @@
     pkgPath: "android/soong/ui/metrics",
     deps: [
         "golang-protobuf-proto",
+        "soong-ui-metrics_upload_proto",
         "soong-ui-metrics_proto",
         "soong-ui-tracer",
     ],
@@ -35,3 +36,11 @@
     ],
 }
 
+bootstrap_go_package {
+    name: "soong-ui-metrics_upload_proto",
+    pkgPath: "android/soong/ui/metrics/upload_proto",
+    deps: ["golang-protobuf-proto"],
+    srcs: [
+        "upload_proto/upload.pb.go",
+    ],
+}
diff --git a/ui/metrics/upload_proto/regen.sh b/ui/metrics/upload_proto/regen.sh
new file mode 100755
index 0000000..4521df7
--- /dev/null
+++ b/ui/metrics/upload_proto/regen.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Generates the golang source file of upload.proto file.
+
+set -e
+
+function die() { echo "ERROR: $1" >&2; exit 1; }
+
+readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
+
+if ! hash aprotoc &>/dev/null; then
+  die "could not find aprotoc. ${error_msg}"
+fi
+
+if ! aprotoc --go_out=paths=source_relative:. upload.proto; then
+  die "build failed. ${error_msg}"
+fi
diff --git a/ui/metrics/upload_proto/upload.pb.go b/ui/metrics/upload_proto/upload.pb.go
new file mode 100644
index 0000000..1b1e5e8
--- /dev/null
+++ b/ui/metrics/upload_proto/upload.pb.go
@@ -0,0 +1,122 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: upload.proto
+
+package soong_metrics_upload_proto
+
+import (
+	fmt "fmt"
+	proto "github.com/golang/protobuf/proto"
+	math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type Upload struct {
+	// The timestamp in milliseconds that the build was created.
+	CreationTimestampMs *uint64 `protobuf:"varint,1,opt,name=creation_timestamp_ms,json=creationTimestampMs" json:"creation_timestamp_ms,omitempty"`
+	// The timestamp in milliseconds when the build was completed.
+	CompletionTimestampMs *uint64 `protobuf:"varint,2,opt,name=completion_timestamp_ms,json=completionTimestampMs" json:"completion_timestamp_ms,omitempty"`
+	// The branch name.
+	BranchName *string `protobuf:"bytes,3,opt,name=branch_name,json=branchName" json:"branch_name,omitempty"`
+	// The target name.
+	TargetName *string `protobuf:"bytes,4,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
+	// A list of metrics filepaths to upload.
+	MetricsFiles         []string `protobuf:"bytes,5,rep,name=metrics_files,json=metricsFiles" json:"metrics_files,omitempty"`
+	XXX_NoUnkeyedLiteral struct{} `json:"-"`
+	XXX_unrecognized     []byte   `json:"-"`
+	XXX_sizecache        int32    `json:"-"`
+}
+
+func (m *Upload) Reset()         { *m = Upload{} }
+func (m *Upload) String() string { return proto.CompactTextString(m) }
+func (*Upload) ProtoMessage()    {}
+func (*Upload) Descriptor() ([]byte, []int) {
+	return fileDescriptor_91b94b655bd2a7e5, []int{0}
+}
+
+func (m *Upload) XXX_Unmarshal(b []byte) error {
+	return xxx_messageInfo_Upload.Unmarshal(m, b)
+}
+func (m *Upload) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	return xxx_messageInfo_Upload.Marshal(b, m, deterministic)
+}
+func (m *Upload) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_Upload.Merge(m, src)
+}
+func (m *Upload) XXX_Size() int {
+	return xxx_messageInfo_Upload.Size(m)
+}
+func (m *Upload) XXX_DiscardUnknown() {
+	xxx_messageInfo_Upload.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_Upload proto.InternalMessageInfo
+
+func (m *Upload) GetCreationTimestampMs() uint64 {
+	if m != nil && m.CreationTimestampMs != nil {
+		return *m.CreationTimestampMs
+	}
+	return 0
+}
+
+func (m *Upload) GetCompletionTimestampMs() uint64 {
+	if m != nil && m.CompletionTimestampMs != nil {
+		return *m.CompletionTimestampMs
+	}
+	return 0
+}
+
+func (m *Upload) GetBranchName() string {
+	if m != nil && m.BranchName != nil {
+		return *m.BranchName
+	}
+	return ""
+}
+
+func (m *Upload) GetTargetName() string {
+	if m != nil && m.TargetName != nil {
+		return *m.TargetName
+	}
+	return ""
+}
+
+func (m *Upload) GetMetricsFiles() []string {
+	if m != nil {
+		return m.MetricsFiles
+	}
+	return nil
+}
+
+func init() {
+	proto.RegisterType((*Upload)(nil), "soong_metrics_upload.Upload")
+}
+
+func init() {
+	proto.RegisterFile("upload.proto", fileDescriptor_91b94b655bd2a7e5)
+}
+
+var fileDescriptor_91b94b655bd2a7e5 = []byte{
+	// 201 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x2d, 0xc8, 0xc9,
+	0x4f, 0x4c, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x29, 0xce, 0xcf, 0xcf, 0x4b, 0x8f,
+	0xcf, 0x4d, 0x2d, 0x29, 0xca, 0x4c, 0x2e, 0x8e, 0x87, 0xc8, 0x29, 0xdd, 0x66, 0xe4, 0x62, 0x0b,
+	0x05, 0x33, 0x85, 0x8c, 0xb8, 0x44, 0x93, 0x8b, 0x52, 0x13, 0x4b, 0x32, 0xf3, 0xf3, 0xe2, 0x4b,
+	0x32, 0x73, 0x53, 0x8b, 0x4b, 0x12, 0x73, 0x0b, 0xe2, 0x73, 0x8b, 0x25, 0x18, 0x15, 0x18, 0x35,
+	0x58, 0x82, 0x84, 0x61, 0x92, 0x21, 0x30, 0x39, 0xdf, 0x62, 0x21, 0x33, 0x2e, 0xf1, 0xe4, 0xfc,
+	0xdc, 0x82, 0x9c, 0x54, 0x4c, 0x5d, 0x4c, 0x60, 0x5d, 0xa2, 0x08, 0x69, 0x64, 0x7d, 0xf2, 0x5c,
+	0xdc, 0x49, 0x45, 0x89, 0x79, 0xc9, 0x19, 0xf1, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0xcc, 0x0a, 0x8c,
+	0x1a, 0x9c, 0x41, 0x5c, 0x10, 0x21, 0xbf, 0xc4, 0xdc, 0x54, 0x90, 0x82, 0x92, 0xc4, 0xa2, 0xf4,
+	0xd4, 0x12, 0x88, 0x02, 0x16, 0x88, 0x02, 0x88, 0x10, 0x58, 0x81, 0x32, 0x17, 0x2f, 0xcc, 0x2b,
+	0x69, 0x99, 0x39, 0xa9, 0xc5, 0x12, 0xac, 0x0a, 0xcc, 0x1a, 0x9c, 0x41, 0x3c, 0x50, 0x41, 0x37,
+	0x90, 0x98, 0x93, 0x4c, 0x94, 0x14, 0x36, 0x5f, 0xc7, 0x83, 0x43, 0x04, 0x10, 0x00, 0x00, 0xff,
+	0xff, 0xe2, 0x01, 0x74, 0x65, 0x20, 0x01, 0x00, 0x00,
+}
diff --git a/ui/metrics/upload_proto/upload.proto b/ui/metrics/upload_proto/upload.proto
new file mode 100644
index 0000000..7a9f080
--- /dev/null
+++ b/ui/metrics/upload_proto/upload.proto
@@ -0,0 +1,35 @@
+// Copyright 2020 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.
+
+syntax = "proto2";
+
+package soong_metrics_upload;
+option go_package = "soong_metrics_upload_proto";
+
+message Upload {
+  // The timestamp in milliseconds that the build was created.
+  optional uint64 creation_timestamp_ms = 1;
+
+  // The timestamp in milliseconds when the build was completed.
+  optional uint64 completion_timestamp_ms = 2;
+
+  // The branch name.
+  optional string branch_name = 3;
+
+  // The target name.
+  optional string target_name = 4;
+
+  // A list of metrics filepaths to upload.
+  repeated string metrics_files = 5;
+}