Merge "Add RBE metrics dump in Soong UI."
diff --git a/android/sdk.go b/android/sdk.go
index e823106..8115b69 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -266,6 +266,9 @@
 	SdkMemberType() SdkMemberType
 }
 
+var _ SdkMemberTypeDependencyTag = (*sdkMemberDependencyTag)(nil)
+var _ ReplaceSourceWithPrebuilt = (*sdkMemberDependencyTag)(nil)
+
 type sdkMemberDependencyTag struct {
 	blueprint.BaseDependencyTag
 	memberType SdkMemberType
@@ -275,6 +278,12 @@
 	return t.memberType
 }
 
+// Prevent dependencies from the sdk/module_exports onto their members from being
+// replaced with a preferred prebuilt.
+func (t *sdkMemberDependencyTag) ReplaceSourceWithPrebuilt() bool {
+	return false
+}
+
 func DependencyTagForSdkMemberType(memberType SdkMemberType) SdkMemberTypeDependencyTag {
 	return &sdkMemberDependencyTag{memberType: memberType}
 }
diff --git a/apex/apex.go b/apex/apex.go
index d0c1a09..b29017d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1750,9 +1750,15 @@
 			return false
 		}
 
+		dt := ctx.OtherModuleDependencyTag(child)
+
+		if _, ok := dt.(android.ExcludeFromApexContentsTag); ok {
+			return false
+		}
+
 		// Check for the direct dependencies that contribute to the payload
-		if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
-			if dt.payload {
+		if adt, ok := dt.(dependencyTag); ok {
+			if adt.payload {
 				return do(ctx, parent, am, false /* externalDep */)
 			}
 			// As soon as the dependency graph crosses the APEX boundary, don't go further.
diff --git a/apex/apex_test.go b/apex/apex_test.go
index c2cb200..f064338 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5791,6 +5791,41 @@
 	}
 }
 
+func TestNonPreferredPrebuiltDependency(t *testing.T) {
+	_, _ = testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			stubs: {
+				versions: ["10000"],
+			},
+			apex_available: ["myapex"],
+		}
+
+		cc_prebuilt_library_shared {
+			name: "mylib",
+			prefer: false,
+			srcs: ["prebuilt.so"],
+			stubs: {
+				versions: ["10000"],
+			},
+			apex_available: ["myapex"],
+		}
+	`)
+}
+
 func TestMain(m *testing.M) {
 	run := func() int {
 		setUp()
diff --git a/docs/perf.md b/docs/perf.md
index 538adff..86a27b4 100644
--- a/docs/perf.md
+++ b/docs/perf.md
@@ -12,6 +12,41 @@
 
 ![trace example](./trace_example.png)
 
+### Critical path
+
+soong_ui logs the wall time of the longest dependency chain compared to the
+elapsed wall time in `$OUT_DIR/soong.log`.  For example:
+```
+critical path took 3m10s
+elapsed time 5m16s
+perfect parallelism ratio 60%
+critical path:
+    0:00 build out/target/product/generic_arm64/obj/FAKE/sepolicy_neverallows_intermediates/policy_2.conf
+    0:04 build out/target/product/generic_arm64/obj/FAKE/sepolicy_neverallows_intermediates/sepolicy_neverallows
+    0:13 build out/target/product/generic_arm64/obj/ETC/plat_sepolicy.cil_intermediates/plat_sepolicy.cil
+    0:01 build out/target/product/generic_arm64/obj/ETC/plat_pub_versioned.cil_intermediates/plat_pub_versioned.cil
+    0:02 build out/target/product/generic_arm64/obj/ETC/vendor_sepolicy.cil_intermediates/vendor_sepolicy.cil
+    0:16 build out/target/product/generic_arm64/obj/ETC/sepolicy_intermediates/sepolicy
+    0:00 build out/target/product/generic_arm64/obj/ETC/plat_seapp_contexts_intermediates/plat_seapp_contexts
+    0:00 Install: out/target/product/generic_arm64/system/etc/selinux/plat_seapp_contexts
+    0:02 build out/target/product/generic_arm64/obj/NOTICE.txt
+    0:00 build out/target/product/generic_arm64/obj/NOTICE.xml.gz
+    0:00 build out/target/product/generic_arm64/system/etc/NOTICE.xml.gz
+    0:01 Installed file list: out/target/product/generic_arm64/installed-files.txt
+    1:00 Target system fs image: out/target/product/generic_arm64/obj/PACKAGING/systemimage_intermediates/system.img
+    0:01 Install system fs image: out/target/product/generic_arm64/system.img
+    0:01 Target vbmeta image: out/target/product/generic_arm64/vbmeta.img
+    1:26 Package target files: out/target/product/generic_arm64/obj/PACKAGING/target_files_intermediates/aosp_arm64-target_files-6663974.zip
+    0:01 Package: out/target/product/generic_arm64/aosp_arm64-img-6663974.zip
+    0:01 Dist: /buildbot/dist_dirs/aosp-master-linux-aosp_arm64-userdebug/6663974/aosp_arm64-img-6663974.zip
+```
+
+If the elapsed time is much longer than the critical path then additional
+parallelism on the build machine will improve total build times.  If there are
+long individual times listed in the critical path then improving build times
+for those steps or adjusting dependencies so that those steps can run earlier
+in the build graph will improve total build times.
+
 ### Soong
 
 Soong can be traced and profiled using the standard Go tools. It understands
diff --git a/java/java_test.go b/java/java_test.go
index 59a2ce7..fb00361 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -25,7 +25,6 @@
 	"strings"
 	"testing"
 
-	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -173,20 +172,6 @@
 	}
 }
 
-func checkModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
-	t.Helper()
-	module := ctx.ModuleForTests(name, variant).Module()
-	deps := []string{}
-	ctx.VisitDirectDeps(module, func(m blueprint.Module) {
-		deps = append(deps, m.Name())
-	})
-	sort.Strings(deps)
-
-	if actual := deps; !reflect.DeepEqual(expected, actual) {
-		t.Errorf("expected %#q, found %#q", expected, actual)
-	}
-}
-
 func TestJavaLinkType(t *testing.T) {
 	testJava(t, `
 		java_library {
@@ -647,7 +632,7 @@
 		}
 	}
 
-	checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+	CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
 		`prebuilt_sdklib.stubs`,
 		`prebuilt_sdklib.stubs.source.test`,
 		`prebuilt_sdklib.stubs.system`,
@@ -675,7 +660,7 @@
 		}
 		`)
 
-	checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+	CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
 		`dex2oatd`,
 		`prebuilt_sdklib`,
 		`sdklib.impl`,
@@ -684,7 +669,7 @@
 		`sdklib.xml`,
 	})
 
-	checkModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+	CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
 		`prebuilt_sdklib.stubs`,
 		`sdklib.impl`,
 		// This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
@@ -715,7 +700,7 @@
 		}
 		`)
 
-	checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+	CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
 		`dex2oatd`,
 		`prebuilt_sdklib`,
 		`sdklib.impl`,
@@ -724,7 +709,7 @@
 		`sdklib.xml`,
 	})
 
-	checkModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+	CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
 		`prebuilt_sdklib.stubs`,
 		`sdklib.impl`,
 		`sdklib.xml`,
@@ -1491,7 +1476,7 @@
 		}
 		`)
 
-	checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+	CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
 		`dex2oatd`,
 		`sdklib.impl`,
 		`sdklib.stubs`,
diff --git a/java/testing.go b/java/testing.go
index f5688e6..94f054e 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -16,9 +16,13 @@
 
 import (
 	"fmt"
+	"reflect"
+	"sort"
+	"testing"
 
 	"android/soong/android"
 	"android/soong/cc"
+	"github.com/google/blueprint"
 )
 
 func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) android.Config {
@@ -216,3 +220,17 @@
 
 	return bp
 }
+
+func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+	t.Helper()
+	module := ctx.ModuleForTests(name, variant).Module()
+	deps := []string{}
+	ctx.VisitDirectDeps(module, func(m blueprint.Module) {
+		deps = append(deps, m.Name())
+	})
+	sort.Strings(deps)
+
+	if actual := deps; !reflect.DeepEqual(expected, actual) {
+		t.Errorf("expected %#q, found %#q", expected, actual)
+	}
+}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 123fe70..c59cd30 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -69,6 +69,28 @@
 	ensureListContains(t, inputs, arm64Output.String())
 }
 
+func TestSdkCompileMultilibOverride(t *testing.T) {
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			native_shared_libs: ["sdkmember"],
+			compile_multilib: "64",
+		}
+
+		cc_library_shared {
+			name: "sdkmember",
+			srcs: ["Test.cpp"],
+			stl: "none",
+			compile_multilib: "64",
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAllCopyRules(`
+.intermediates/sdkmember/android_arm64_armv8-a_shared/sdkmember.so -> arm64/lib/sdkmember.so
+`))
+}
+
 func TestBasicSdkWithCc(t *testing.T) {
 	result := testSdkWithCc(t, `
 		sdk {
@@ -79,6 +101,8 @@
 		cc_library_shared {
 			name: "sdkmember",
 			system_shared_libs: [],
+			stl: "none",
+			apex_available: ["mysdkapex"],
 		}
 
 		sdk_snapshot {
@@ -152,6 +176,13 @@
 			key: "myapex.key",
 			certificate: ":myapex.cert",
 		}
+
+		apex {
+			name: "mysdkapex",
+			native_shared_libs: ["sdkmember"],
+			key: "myapex.key",
+			certificate: ":myapex.cert",
+		}
 	`)
 
 	sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_myapex").Rule("toc").Output
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 7496b20..79da3f0 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -16,6 +16,8 @@
 
 import (
 	"testing"
+
+	"android/soong/java"
 )
 
 func testSdkWithJava(t *testing.T, bp string) *testSdkResult {
@@ -26,6 +28,9 @@
 		"resource.test":          nil,
 		"aidl/foo/bar/Test.aidl": nil,
 
+		// For java_import
+		"prebuilt.jar": nil,
+
 		// For java_sdk_library
 		"api/current.txt":                                   nil,
 		"api/removed.txt":                                   nil,
@@ -85,6 +90,52 @@
 
 // Contains tests for SDK members provided by the java package.
 
+func TestSdkDependsOnSourceEvenWhenPrebuiltPreferred(t *testing.T) {
+	result := testSdkWithJava(t, `
+		sdk {
+			name: "mysdk",
+			java_header_libs: ["sdkmember"],
+		}
+
+		java_library {
+			name: "sdkmember",
+			srcs: ["Test.java"],
+			system_modules: "none",
+			sdk_version: "none",
+		}
+
+		java_import {
+			name: "sdkmember",
+			prefer: true,
+			jars: ["prebuilt.jar"],
+		}
+	`)
+
+	// Make sure that the mysdk module depends on "sdkmember" and not "prebuilt_sdkmember".
+	java.CheckModuleDependencies(t, result.ctx, "mysdk", "android_common", []string{"sdkmember"})
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`// This is auto-generated. DO NOT EDIT.
+
+java_import {
+    name: "mysdk_sdkmember@current",
+    sdk_member_name: "sdkmember",
+    jars: ["java/sdkmember.jar"],
+}
+
+java_import {
+    name: "sdkmember",
+    prefer: false,
+    jars: ["java/sdkmember.jar"],
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    java_header_libs: ["mysdk_sdkmember@current"],
+}
+`))
+}
+
 func TestBasicSdkWithJavaLibrary(t *testing.T) {
 	result := testSdkWithJava(t, `
 		sdk {
diff --git a/sdk/sdk.go b/sdk/sdk.go
index b9b8199..3e76008 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -218,7 +218,7 @@
 			Compile_multilib *string
 		}
 		p := &props{Compile_multilib: proptools.StringPtr("both")}
-		ctx.AppendProperties(p)
+		ctx.PrependProperties(p)
 	})
 	return s
 }
@@ -330,6 +330,11 @@
 	blueprint.BaseDependencyTag
 }
 
+// Mark this tag so dependencies that use it are excluded from APEX contents.
+func (t dependencyTag) ExcludeFromApexContents() {}
+
+var _ android.ExcludeFromApexContentsTag = dependencyTag{}
+
 // For dependencies from an in-development version of an SDK member to frozen versions of the same member
 // e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12
 type sdkMemberVersionedDepTag struct {
diff --git a/sdk/testing.go b/sdk/testing.go
index 40abdcd..4d029e4 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -44,14 +44,15 @@
 	` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
 
 	mockFS := map[string][]byte{
-		"build/make/target/product/security":         nil,
-		"apex_manifest.json":                         nil,
-		"system/sepolicy/apex/myapex-file_contexts":  nil,
-		"system/sepolicy/apex/myapex2-file_contexts": nil,
-		"myapex.avbpubkey":                           nil,
-		"myapex.pem":                                 nil,
-		"myapex.x509.pem":                            nil,
-		"myapex.pk8":                                 nil,
+		"build/make/target/product/security":           nil,
+		"apex_manifest.json":                           nil,
+		"system/sepolicy/apex/myapex-file_contexts":    nil,
+		"system/sepolicy/apex/myapex2-file_contexts":   nil,
+		"system/sepolicy/apex/mysdkapex-file_contexts": nil,
+		"myapex.avbpubkey":                             nil,
+		"myapex.pem":                                   nil,
+		"myapex.x509.pem":                              nil,
+		"myapex.pk8":                                   nil,
 	}
 
 	cc.GatherRequiredFilesForTest(mockFS)