Merge "Don't assume host arch is always x86"
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 78d8428..a4c0677 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -946,7 +946,7 @@
 	`)
 }
 
-func TestVendorSnapshot(t *testing.T) {
+func TestVendorSnapshotCapture(t *testing.T) {
 	bp := `
 	cc_library {
 		name: "libvndk",
@@ -1079,6 +1079,215 @@
 	}
 }
 
+func TestVendorSnapshotUse(t *testing.T) {
+	frameworkBp := `
+	cc_library {
+		name: "libvndk",
+		vendor_available: true,
+		vndk: {
+			enabled: true,
+		},
+		nocrt: true,
+		compile_multilib: "64",
+	}
+
+	cc_library {
+		name: "libvendor",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+
+	cc_binary {
+		name: "bin",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+`
+
+	vndkBp := `
+	vndk_prebuilt_shared {
+		name: "libvndk",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor_available: true,
+		vndk: {
+			enabled: true,
+		},
+		arch: {
+			arm64: {
+				srcs: ["libvndk.so"],
+			},
+		},
+	}
+`
+
+	vendorProprietaryBp := `
+	cc_library {
+		name: "libvendor_without_snapshot",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		compile_multilib: "64",
+	}
+
+	cc_library_shared {
+		name: "libclient",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		shared_libs: ["libvndk"],
+		static_libs: ["libvendor", "libvendor_without_snapshot"],
+		compile_multilib: "64",
+	}
+
+	cc_binary {
+		name: "bin_without_snapshot",
+		vendor: true,
+		nocrt: true,
+		no_libcrt: true,
+		stl: "none",
+		system_shared_libs: [],
+		static_libs: ["libvndk"],
+		compile_multilib: "64",
+	}
+
+	vendor_snapshot_static {
+		name: "libvndk",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvndk.a",
+			},
+		},
+	}
+
+	vendor_snapshot_shared {
+		name: "libvendor",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvendor.so",
+			},
+		},
+	}
+
+	vendor_snapshot_static {
+		name: "libvendor",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "libvendor.a",
+			},
+		},
+	}
+
+	vendor_snapshot_binary {
+		name: "bin",
+		version: "BOARD",
+		target_arch: "arm64",
+		vendor: true,
+		arch: {
+			arm64: {
+				src: "bin",
+			},
+		},
+	}
+`
+	depsBp := GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"deps/Android.bp":      []byte(depsBp),
+		"framework/Android.bp": []byte(frameworkBp),
+		"vendor/Android.bp":    []byte(vendorProprietaryBp),
+		"vendor/libvndk.a":     nil,
+		"vendor/libvendor.a":   nil,
+		"vendor/libvendor.so":  nil,
+		"vendor/bin":           nil,
+		"vndk/Android.bp":      []byte(vndkBp),
+		"vndk/libvndk.so":      nil,
+	}
+
+	config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	ctx := CreateTestContext()
+	ctx.Register(config)
+
+	_, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared"
+	staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
+	binaryVariant := "android_vendor.BOARD_arm64_armv8-a"
+
+	// libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot
+	libclientLdRule := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld")
+	libclientFlags := libclientLdRule.Args["libFlags"]
+
+	for _, input := range [][]string{
+		[]string{sharedVariant, "libvndk.vndk.BOARD.arm64"},
+		[]string{staticVariant, "libvendor.vendor_static.BOARD.arm64"},
+		[]string{staticVariant, "libvendor_without_snapshot"},
+	} {
+		outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
+		if !strings.Contains(libclientFlags, outputPaths[0].String()) {
+			t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientFlags)
+		}
+	}
+
+	// bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64
+	binWithoutSnapshotLdRule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld")
+	binWithoutSnapshotFlags := binWithoutSnapshotLdRule.Args["libFlags"]
+	libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"})
+	if !strings.Contains(binWithoutSnapshotFlags, libVndkStaticOutputPaths[0].String()) {
+		t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
+			libVndkStaticOutputPaths[0], binWithoutSnapshotFlags)
+	}
+
+	// libvendor.so is installed by libvendor.vendor_shared.BOARD.arm64
+	ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so")
+
+	// libvendor_without_snapshot.so is installed by libvendor_without_snapshot
+	ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
+
+	// bin is installed by bin.vendor_binary.BOARD.arm64
+	ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin")
+
+	// bin_without_snapshot is installed by bin_without_snapshot
+	ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
+
+	// libvendor and bin don't have vendor.BOARD variant
+	libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
+	if inList(sharedVariant, libvendorVariants) {
+		t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
+	}
+
+	binVariants := ctx.ModuleVariantsForTests("bin")
+	if inList(binaryVariant, binVariants) {
+		t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
+	}
+}
+
 func TestVendorSnapshotSanitizer(t *testing.T) {
 	bp := `
 	vendor_snapshot_static {
diff --git a/cc/testing.go b/cc/testing.go
index 06e5f83..52f0829 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -527,7 +527,9 @@
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
 	ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
+	ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
 	ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
+	ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
 	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
 	android.RegisterPrebuiltMutators(ctx)
 	RegisterRequiredBuildComponentsForTest(ctx)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index f22ee47..3ef8b8d 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -130,14 +130,20 @@
 
 // Add a new library path to the map. Ensure that the build path to the library exists.
 func (libPaths LibraryPaths) AddLibraryPath(ctx android.PathContext, lib string, hostPath, installPath android.Path) {
-	if hostPath != nil {
-		// Add a library only if the build path to it is known.
+	if hostPath != nil && installPath != nil {
+		// Add a library only if the build and install path to it is known.
 		libPaths.addLibraryPath(ctx, lib, hostPath, installPath)
-	} else if !ctx.Config().AllowMissingDependencies() {
-		// Error on libraries with unknown build paths, unless missing dependencies are allowed.
-		android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib)
+	} else if ctx.Config().AllowMissingDependencies() {
+		// If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is
+		// not found. However, this is likely to result is disabling dexpreopt, as it won't be
+		// possible to construct class loader context without on-host and on-device library paths.
 	} else {
-		// Not adding a library to the map will likely result in disabling dexpreopt.
+		// Error on libraries with unknown paths.
+		if hostPath == nil {
+			android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib)
+		} else {
+			android.ReportPathErrorf(ctx, "unknown install path to <uses-library> '%s'", lib)
+		}
 	}
 }
 
diff --git a/java/app.go b/java/app.go
index 3dfdfdc..406894d 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1915,11 +1915,11 @@
 		if hasFrameworkLibs {
 			// Dexpreopt needs paths to the dex jars of these libraries in order to construct
 			// class loader context for dex2oat. Add them as a dependency with a special tag.
-			ctx.AddVariationDependencies(nil, usesLibTag,
+			ctx.AddVariationDependencies(nil, usesLibCompatTag,
 				"org.apache.http.legacy",
 				"android.hidl.base-V1.0-java",
 				"android.hidl.manager-V1.0-java")
-			ctx.AddVariationDependencies(nil, usesLibTag, optionalUsesLibs...)
+			ctx.AddVariationDependencies(nil, usesLibCompatTag, optionalUsesLibs...)
 		}
 	}
 }
@@ -1937,30 +1937,27 @@
 	usesLibPaths := make(dexpreopt.LibraryPaths)
 
 	if !ctx.Config().UnbundledBuild() {
-		ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) {
-			dep := ctx.OtherModuleName(m)
-			if lib, ok := m.(Dependency); ok {
-				buildPath := lib.DexJarBuildPath()
-				if buildPath == nil {
-					ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must"+
-						" produce a dex jar, does it have installable: true?", dep)
-					return
-				}
+		ctx.VisitDirectDeps(func(m android.Module) {
+			tag := ctx.OtherModuleDependencyTag(m)
+			if tag == usesLibTag || tag == usesLibCompatTag {
+				dep := ctx.OtherModuleName(m)
 
-				var devicePath string
-				installPath := lib.DexJarInstallPath()
-				if installPath == nil {
-					devicePath = filepath.Join("/system/framework", dep+".jar")
+				if lib, ok := m.(Dependency); ok {
+					buildPath := lib.DexJarBuildPath()
+					installPath := lib.DexJarInstallPath()
+					if installPath == nil && tag == usesLibCompatTag {
+						// assume that compatibility libraries are in /system/framework
+						installPath = android.PathForModuleInstall(ctx, "framework", dep+".jar")
+					}
+					usesLibPaths.AddLibraryPath(ctx, dep, buildPath, installPath)
+
+				} else if ctx.Config().AllowMissingDependencies() {
+					ctx.AddMissingDependencies([]string{dep})
+
 				} else {
-					devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
+					ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be "+
+						"a java library", dep)
 				}
-
-				usesLibPaths[dep] = &dexpreopt.LibraryPath{buildPath, devicePath}
-			} else if ctx.Config().AllowMissingDependencies() {
-				ctx.AddMissingDependencies([]string{dep})
-			} else {
-				ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be "+
-					"a java library", dep)
 			}
 		})
 	}
diff --git a/java/java.go b/java/java.go
index 0690418..c568ec4 100644
--- a/java/java.go
+++ b/java/java.go
@@ -566,6 +566,7 @@
 	certificateTag        = dependencyTag{name: "certificate"}
 	instrumentationForTag = dependencyTag{name: "instrumentation_for"}
 	usesLibTag            = dependencyTag{name: "uses-library"}
+	usesLibCompatTag      = dependencyTag{name: "uses-library-compat"}
 	extraLintCheckTag     = dependencyTag{name: "extra-lint-check"}
 )