Merge "Make highmem classification of metalava optional"
diff --git a/android/config.go b/android/config.go
index 004b743..42a286c 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1336,11 +1336,6 @@
 	return len(l.jars)
 }
 
-// Apex component of idx-th pair on the list.
-func (l *ConfiguredJarList) apex(idx int) string {
-	return l.apexes[idx]
-}
-
 // Jar component of idx-th pair on the list.
 func (l *ConfiguredJarList) Jar(idx int) string {
 	return l.jars[idx]
@@ -1354,7 +1349,7 @@
 // If the list contains the given (apex, jar) pair.
 func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool {
 	for i := 0; i < l.Len(); i++ {
-		if apex == l.apex(i) && jar == l.Jar(i) {
+		if apex == l.apexes[i] && jar == l.jars[i] {
 			return true
 		}
 	}
@@ -1378,7 +1373,7 @@
 	jars := make([]string, 0, l.Len())
 
 	for i, jar := range l.jars {
-		apex := l.apex(i)
+		apex := l.apexes[i]
 		if !list.containsApexJarPair(apex, jar) {
 			apexes = append(apexes, apex)
 			jars = append(jars, jar)
@@ -1404,7 +1399,7 @@
 	pairs := make([]string, 0, l.Len())
 
 	for i, jar := range l.jars {
-		apex := l.apex(i)
+		apex := l.apexes[i]
 		pairs = append(pairs, apex+":"+jar)
 	}
 
diff --git a/android/paths.go b/android/paths.go
index 4eb9d20..2fb5f25 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1237,7 +1237,12 @@
 type InstallPath struct {
 	basePath
 
-	baseDir string // "../" for Make paths to convert "out/soong" to "out", "" for Soong paths
+	// partitionDir is the part of the InstallPath that is automatically determined according to the context.
+	// For example, it is host/<os>-<arch> for host modules, and target/product/<device>/<partition> for device modules.
+	partitionDir string
+
+	// makePath indicates whether this path is for Soong (false) or Make (true).
+	makePath bool
 }
 
 func (p InstallPath) buildDir() string {
@@ -1250,7 +1255,23 @@
 func (p InstallPath) writablePath() {}
 
 func (p InstallPath) String() string {
-	return filepath.Join(p.config.buildDir, p.baseDir, p.path)
+	if p.makePath {
+		// Make path starts with out/ instead of out/soong.
+		return filepath.Join(p.config.buildDir, "../", p.path)
+	} else {
+		return filepath.Join(p.config.buildDir, p.path)
+	}
+}
+
+// PartitionDir returns the path to the partition where the install path is rooted at. It is
+// out/soong/target/product/<device>/<partition> for device modules, and out/soong/host/<os>-<arch> for host modules.
+// The ./soong is dropped if the install path is for Make.
+func (p InstallPath) PartitionDir() string {
+	if p.makePath {
+		return filepath.Join(p.config.buildDir, "../", p.partitionDir)
+	} else {
+		return filepath.Join(p.config.buildDir, p.partitionDir)
+	}
 }
 
 // Join creates a new InstallPath with paths... joined with the current path. The
@@ -1271,7 +1292,7 @@
 // ToMakePath returns a new InstallPath that points to Make's install directory instead of Soong's,
 // i.e. out/ instead of out/soong/.
 func (p InstallPath) ToMakePath() InstallPath {
-	p.baseDir = "../"
+	p.makePath = true
 	return p
 }
 
@@ -1301,10 +1322,10 @@
 func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, debug bool,
 	pathComponents ...string) InstallPath {
 
-	var outPaths []string
+	var partionPaths []string
 
 	if os.Class == Device {
-		outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
+		partionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
 	} else {
 		osName := os.String()
 		if os == Linux {
@@ -1320,30 +1341,33 @@
 		if os.Class == Host && (arch == X86_64 || arch == Common) {
 			archName = "x86"
 		}
-		outPaths = []string{"host", osName + "-" + archName, partition}
+		partionPaths = []string{"host", osName + "-" + archName, partition}
 	}
 	if debug {
-		outPaths = append([]string{"debug"}, outPaths...)
+		partionPaths = append([]string{"debug"}, partionPaths...)
 	}
-	outPaths = append(outPaths, pathComponents...)
 
-	path, err := validatePath(outPaths...)
+	partionPath, err := validatePath(partionPaths...)
 	if err != nil {
 		reportPathError(ctx, err)
 	}
 
-	ret := InstallPath{basePath{path, ctx.Config(), ""}, ""}
+	base := InstallPath{
+		basePath:     basePath{partionPath, ctx.Config(), ""},
+		partitionDir: partionPath,
+		makePath:     false,
+	}
 
-	return ret
+	return base.Join(ctx, pathComponents...)
 }
 
 func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
-	paths = append([]string{prefix}, paths...)
-	path, err := validatePath(paths...)
-	if err != nil {
-		reportPathError(ctx, err)
+	base := InstallPath{
+		basePath:     basePath{prefix, ctx.Config(), ""},
+		partitionDir: prefix,
+		makePath:     false,
 	}
-	return InstallPath{basePath{path, ctx.Config(), ""}, ""}
+	return base.Join(ctx, paths...)
 }
 
 func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
@@ -1378,8 +1402,12 @@
 				partition += "/system"
 			}
 		} else if ctx.InstallInVendorRamdisk() {
+			// The module is only available after switching root into
+			// /first_stage_ramdisk. To expose the module before switching root
+			// on a device without a dedicated recovery partition, install the
+			// recovery variant.
 			if ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() {
-				partition = "recovery/root/first_stage_ramdisk"
+				partition = "vendor-ramdisk/first_stage_ramdisk"
 			} else {
 				partition = "vendor-ramdisk"
 			}
diff --git a/android/paths_test.go b/android/paths_test.go
index 9ecf4a1..51e4ba5 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -264,10 +264,11 @@
 	deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}}
 
 	testCases := []struct {
-		name string
-		ctx  *moduleInstallPathContextImpl
-		in   []string
-		out  string
+		name         string
+		ctx          *moduleInstallPathContextImpl
+		in           []string
+		out          string
+		partitionDir string
 	}{
 		{
 			name: "host binary",
@@ -277,8 +278,9 @@
 					target: hostTarget,
 				},
 			},
-			in:  []string{"bin", "my_test"},
-			out: "host/linux-x86/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "host/linux-x86/bin/my_test",
+			partitionDir: "host/linux-x86",
 		},
 
 		{
@@ -289,8 +291,9 @@
 					target: deviceTarget,
 				},
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/system/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/system/bin/my_test",
+			partitionDir: "target/product/test_device/system",
 		},
 		{
 			name: "vendor binary",
@@ -303,8 +306,9 @@
 					},
 				},
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/vendor/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/vendor/bin/my_test",
+			partitionDir: "target/product/test_device/vendor",
 		},
 		{
 			name: "odm binary",
@@ -317,8 +321,9 @@
 					},
 				},
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/odm/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/odm/bin/my_test",
+			partitionDir: "target/product/test_device/odm",
 		},
 		{
 			name: "product binary",
@@ -331,8 +336,9 @@
 					},
 				},
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/product/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/product/bin/my_test",
+			partitionDir: "target/product/test_device/product",
 		},
 		{
 			name: "system_ext binary",
@@ -345,8 +351,9 @@
 					},
 				},
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/system_ext/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/system_ext/bin/my_test",
+			partitionDir: "target/product/test_device/system_ext",
 		},
 		{
 			name: "root binary",
@@ -357,8 +364,9 @@
 				},
 				inRoot: true,
 			},
-			in:  []string{"my_test"},
-			out: "target/product/test_device/root/my_test",
+			in:           []string{"my_test"},
+			out:          "target/product/test_device/root/my_test",
+			partitionDir: "target/product/test_device/root",
 		},
 		{
 			name: "recovery binary",
@@ -369,8 +377,9 @@
 				},
 				inRecovery: true,
 			},
-			in:  []string{"bin/my_test"},
-			out: "target/product/test_device/recovery/root/system/bin/my_test",
+			in:           []string{"bin/my_test"},
+			out:          "target/product/test_device/recovery/root/system/bin/my_test",
+			partitionDir: "target/product/test_device/recovery/root/system",
 		},
 		{
 			name: "recovery root binary",
@@ -382,8 +391,9 @@
 				inRecovery: true,
 				inRoot:     true,
 			},
-			in:  []string{"my_test"},
-			out: "target/product/test_device/recovery/root/my_test",
+			in:           []string{"my_test"},
+			out:          "target/product/test_device/recovery/root/my_test",
+			partitionDir: "target/product/test_device/recovery/root",
 		},
 
 		{
@@ -395,8 +405,9 @@
 				},
 				inData: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data",
 		},
 		{
 			name: "vendor native test binary",
@@ -410,8 +421,9 @@
 				},
 				inData: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data",
 		},
 		{
 			name: "odm native test binary",
@@ -425,8 +437,9 @@
 				},
 				inData: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data",
 		},
 		{
 			name: "product native test binary",
@@ -440,8 +453,9 @@
 				},
 				inData: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data",
 		},
 
 		{
@@ -456,8 +470,9 @@
 				},
 				inData: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data",
 		},
 
 		{
@@ -469,8 +484,9 @@
 				},
 				inSanitizerDir: true,
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/data/asan/system/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/data/asan/system/bin/my_test",
+			partitionDir: "target/product/test_device/data/asan/system",
 		},
 		{
 			name: "sanitized vendor binary",
@@ -484,8 +500,9 @@
 				},
 				inSanitizerDir: true,
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/data/asan/vendor/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/data/asan/vendor/bin/my_test",
+			partitionDir: "target/product/test_device/data/asan/vendor",
 		},
 		{
 			name: "sanitized odm binary",
@@ -499,8 +516,9 @@
 				},
 				inSanitizerDir: true,
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/data/asan/odm/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/data/asan/odm/bin/my_test",
+			partitionDir: "target/product/test_device/data/asan/odm",
 		},
 		{
 			name: "sanitized product binary",
@@ -514,8 +532,9 @@
 				},
 				inSanitizerDir: true,
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/data/asan/product/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/data/asan/product/bin/my_test",
+			partitionDir: "target/product/test_device/data/asan/product",
 		},
 
 		{
@@ -530,8 +549,9 @@
 				},
 				inSanitizerDir: true,
 			},
-			in:  []string{"bin", "my_test"},
-			out: "target/product/test_device/data/asan/system_ext/bin/my_test",
+			in:           []string{"bin", "my_test"},
+			out:          "target/product/test_device/data/asan/system_ext/bin/my_test",
+			partitionDir: "target/product/test_device/data/asan/system_ext",
 		},
 
 		{
@@ -544,8 +564,9 @@
 				inData:         true,
 				inSanitizerDir: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/asan/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data/asan/data",
 		},
 		{
 			name: "sanitized vendor native test binary",
@@ -560,8 +581,9 @@
 				inData:         true,
 				inSanitizerDir: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/asan/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data/asan/data",
 		},
 		{
 			name: "sanitized odm native test binary",
@@ -576,8 +598,9 @@
 				inData:         true,
 				inSanitizerDir: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/asan/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data/asan/data",
 		},
 		{
 			name: "sanitized product native test binary",
@@ -592,8 +615,9 @@
 				inData:         true,
 				inSanitizerDir: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/asan/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data/asan/data",
 		},
 		{
 			name: "sanitized system_ext native test binary",
@@ -608,8 +632,9 @@
 				inData:         true,
 				inSanitizerDir: true,
 			},
-			in:  []string{"nativetest", "my_test"},
-			out: "target/product/test_device/data/asan/data/nativetest/my_test",
+			in:           []string{"nativetest", "my_test"},
+			out:          "target/product/test_device/data/asan/data/nativetest/my_test",
+			partitionDir: "target/product/test_device/data/asan/data",
 		}, {
 			name: "device testcases",
 			ctx: &moduleInstallPathContextImpl{
@@ -619,8 +644,9 @@
 				},
 				inTestcases: true,
 			},
-			in:  []string{"my_test", "my_test_bin"},
-			out: "target/product/test_device/testcases/my_test/my_test_bin",
+			in:           []string{"my_test", "my_test_bin"},
+			out:          "target/product/test_device/testcases/my_test/my_test_bin",
+			partitionDir: "target/product/test_device/testcases",
 		}, {
 			name: "host testcases",
 			ctx: &moduleInstallPathContextImpl{
@@ -630,8 +656,9 @@
 				},
 				inTestcases: true,
 			},
-			in:  []string{"my_test", "my_test_bin"},
-			out: "host/linux-x86/testcases/my_test/my_test_bin",
+			in:           []string{"my_test", "my_test_bin"},
+			out:          "host/linux-x86/testcases/my_test/my_test_bin",
+			partitionDir: "host/linux-x86/testcases",
 		}, {
 			name: "forced host testcases",
 			ctx: &moduleInstallPathContextImpl{
@@ -643,8 +670,9 @@
 				forceOS:     &Linux,
 				forceArch:   &X86,
 			},
-			in:  []string{"my_test", "my_test_bin"},
-			out: "host/linux-x86/testcases/my_test/my_test_bin",
+			in:           []string{"my_test", "my_test_bin"},
+			out:          "host/linux-x86/testcases/my_test/my_test_bin",
+			partitionDir: "host/linux-x86/testcases",
 		},
 	}
 
@@ -657,10 +685,48 @@
 					output.basePath.path,
 					tc.out)
 			}
+			if output.partitionDir != tc.partitionDir {
+				t.Errorf("unexpected partitionDir:\n got: %q\nwant: %q\n",
+					output.partitionDir, tc.partitionDir)
+			}
 		})
 	}
 }
 
+func TestBaseDirForInstallPath(t *testing.T) {
+	testConfig := pathTestConfig("")
+	deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}}
+
+	ctx := &moduleInstallPathContextImpl{
+		baseModuleContext: baseModuleContext{
+			os:     deviceTarget.Os,
+			target: deviceTarget,
+		},
+	}
+	ctx.baseModuleContext.config = testConfig
+
+	actual := PathForModuleInstall(ctx, "foo", "bar")
+	expectedBaseDir := "target/product/test_device/system"
+	if actual.partitionDir != expectedBaseDir {
+		t.Errorf("unexpected partitionDir:\n got: %q\nwant: %q\n", actual.partitionDir, expectedBaseDir)
+	}
+	expectedRelPath := "foo/bar"
+	if actual.Rel() != expectedRelPath {
+		t.Errorf("unexpected Rel():\n got: %q\nwant: %q\n", actual.Rel(), expectedRelPath)
+	}
+
+	actualAfterJoin := actual.Join(ctx, "baz")
+	// partitionDir is preserved even after joining
+	if actualAfterJoin.partitionDir != expectedBaseDir {
+		t.Errorf("unexpected partitionDir after joining:\n got: %q\nwant: %q\n", actualAfterJoin.partitionDir, expectedBaseDir)
+	}
+	// Rel() is updated though
+	expectedRelAfterJoin := "baz"
+	if actualAfterJoin.Rel() != expectedRelAfterJoin {
+		t.Errorf("unexpected Rel() after joining:\n got: %q\nwant: %q\n", actualAfterJoin.Rel(), expectedRelAfterJoin)
+	}
+}
+
 func TestDirectorySortedPaths(t *testing.T) {
 	config := TestConfig("out", nil, "", map[string][]byte{
 		"Android.bp": nil,
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 07e78af..c7223c4 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -278,6 +278,7 @@
 libcutils_sockets(minSdkVersion:29)
 libdiagnose_usb(minSdkVersion:(no version))
 libdl(minSdkVersion:(no version))
+libdmabufheap(minSdkVersion:29)
 libeigen(minSdkVersion:(no version))
 libfifo(minSdkVersion:29)
 libFLAC(minSdkVersion:29)
diff --git a/cc/cc.go b/cc/cc.go
index c1a4327..c93bdeb 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -255,10 +255,18 @@
 	// file
 	Logtags []string
 
-	// Make this module available when building for ramdisk
+	// Make this module available when building for ramdisk.
+	// On device without a dedicated recovery partition, the module is only
+	// available after switching root into
+	// /first_stage_ramdisk. To expose the module before switching root, install
+	// the recovery variant instead.
 	Ramdisk_available *bool
 
-	// Make this module available when building for vendor ramdisk
+	// Make this module available when building for vendor ramdisk.
+	// On device without a dedicated recovery partition, the module is only
+	// available after switching root into
+	// /first_stage_ramdisk. To expose the module before switching root, install
+	// the recovery variant instead.
 	Vendor_ramdisk_available *bool
 
 	// Make this module available when building for recovery
diff --git a/cc/vndk.go b/cc/vndk.go
index 6d5b074..7d8777c 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -740,7 +740,7 @@
 	/*
 		module_paths.txt contains paths on which VNDK modules are defined.
 		e.g.,
-			libbase.so system/core/base
+			libbase.so system/libbase
 			libc.so bionic/libc
 			...
 	*/
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 774a872..a1b0c8e 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -470,7 +470,13 @@
 		ctx.Fatal("done")
 	}
 
-	toBuild := build.BuildAll
+	var toBuild int
+	if _, ok := config.Environment().Get("USE_BAZEL"); ok {
+		toBuild = build.BuildAllWithBazel
+	} else {
+		toBuild = build.BuildAll
+	}
+
 	if config.Checkbuild() {
 		toBuild |= build.RunBuildTests
 	}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 337ad88..44b8149 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -59,9 +59,17 @@
 	Filename_from_src *bool `android:"arch_variant"`
 
 	// Make this module available when building for ramdisk.
+	// On device without a dedicated recovery partition, the module is only
+	// available after switching root into
+	// /first_stage_ramdisk. To expose the module before switching root, install
+	// the recovery variant instead.
 	Ramdisk_available *bool
 
 	// Make this module available when building for vendor ramdisk.
+	// On device without a dedicated recovery partition, the module is only
+	// available after switching root into
+	// /first_stage_ramdisk. To expose the module before switching root, install
+	// the recovery variant instead.
 	Vendor_ramdisk_available *bool
 
 	// Make this module available when building for recovery.
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 6f40ae4..7e5c344 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -66,9 +66,17 @@
 	Symlinks []string `android:"arch_variant"`
 
 	// Make this module available when building for ramdisk.
+	// On device without a dedicated recovery partition, the module is only
+	// available after switching root into
+	// /first_stage_ramdisk. To expose the module before switching root, install
+	// the recovery variant instead.
 	Ramdisk_available *bool
 
 	// Make this module available when building for vendor ramdisk.
+	// On device without a dedicated recovery partition, the module is only
+	// available after switching root into
+	// /first_stage_ramdisk. To expose the module before switching root, install
+	// the recovery variant instead.
 	Vendor_ramdisk_available *bool
 
 	// Make this module available when building for recovery.
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index 4ef2721..c314b7b 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -39,6 +39,7 @@
         "blueprint-microfactory",
     ],
     srcs: [
+        "bazel.go",
         "build.go",
         "cleanbuild.go",
         "config.go",
diff --git a/ui/build/bazel.go b/ui/build/bazel.go
new file mode 100644
index 0000000..c5702c0
--- /dev/null
+++ b/ui/build/bazel.go
@@ -0,0 +1,54 @@
+// 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.
+
+package build
+
+import (
+	"path/filepath"
+	"strings"
+)
+
+func runBazel(ctx Context, config Config) {
+	// "droid" is the default ninja target.
+	outputGroups := "droid"
+	if len(config.ninjaArgs) > 0 {
+		// At this stage, the residue slice of args passed to ninja
+		// are the ninja targets to build, which can correspond directly
+		// to ninja_build's output_groups.
+		outputGroups = strings.Join(config.ninjaArgs, ",")
+	}
+
+	bazelExecutable := filepath.Join("tools", "bazel")
+	args := []string{
+		"build",
+		"--verbose_failures",
+		"--show_progress_rate_limit=0.05",
+		"--color=yes",
+		"--curses=yes",
+		"--show_timestamps",
+		"--announce_rc",
+		"--output_groups=" + outputGroups,
+		"//:" + config.TargetProduct() + "-" + config.TargetBuildVariant(),
+	}
+
+	cmd := Command(ctx, config, "bazel", bazelExecutable, args...)
+
+	cmd.Environment.Set("DIST_DIR", config.DistDir())
+	cmd.Environment.Set("SHELL", "/bin/bash")
+
+	ctx.Println(cmd.Cmd)
+	cmd.Dir = filepath.Join(config.OutDir(), "..")
+	ctx.Status.Status("Starting Bazel..")
+	cmd.RunAndStreamOrFatal()
+}
diff --git a/ui/build/build.go b/ui/build/build.go
index 396f54c..1cf2023 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -84,8 +84,10 @@
 	BuildSoong         = 1 << iota
 	BuildKati          = 1 << iota
 	BuildNinja         = 1 << iota
+	BuildBazel         = 1 << iota
 	RunBuildTests      = 1 << iota
 	BuildAll           = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
+	BuildAllWithBazel  = BuildProductConfig | BuildSoong | BuildKati | BuildBazel
 )
 
 func checkProblematicFiles(ctx Context) {
@@ -257,6 +259,10 @@
 		// Run ninja
 		runNinja(ctx, config)
 	}
+
+	if what&BuildBazel != 0 {
+		runBazel(ctx, config)
+	}
 }
 
 // distGzipFile writes a compressed copy of src to the distDir if dist is enabled.  Failures