Merge "Generate fake versions of modules excluded in directed vendor snapshot."
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 6403547..b1c1b2e 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -266,7 +266,7 @@
 	}
 }
 
-func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool) {
+func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool, fake bool) {
 	t.Helper()
 	mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer)
 	if !ok {
@@ -282,8 +282,14 @@
 
 	if include {
 		out := singleton.Output(snapshotPath)
-		if out.Input.String() != outputFiles[0].String() {
-			t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
+		if fake {
+			if out.Rule == nil {
+				t.Errorf("Missing rule for module %q output file %q", moduleName, outputFiles[0])
+			}
+		} else {
+			if out.Input.String() != outputFiles[0].String() {
+				t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
+			}
 		}
 	} else {
 		out := singleton.MaybeOutput(snapshotPath)
@@ -294,11 +300,15 @@
 }
 
 func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
-	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true)
+	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, false)
 }
 
 func checkSnapshotExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
-	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false)
+	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false, false)
+}
+
+func checkSnapshotRule(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
+	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, true)
 }
 
 func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) {
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 35fc1c1..7077b71 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -239,10 +239,6 @@
 	if _, ok := m.linker.(*llndkHeadersDecorator); ok {
 		return false
 	}
-	// If we are using directed snapshot AND we have to exclude this module, skip this
-	if image.excludeFromDirectedSnapshot(cfg, m.BaseModuleName()) {
-		return false
-	}
 
 	// Libraries
 	if l, ok := m.linker.(snapshotLibraryInterface); ok {
@@ -371,18 +367,19 @@
 
 	var headers android.Paths
 
-	copyFile := copyFileRule
-	if c.fake {
-		// All prebuilt binaries and headers are installed by copyFile function. This makes a fake
-		// snapshot just touch prebuilts and headers, rather than installing real files.
-		copyFile = func(ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
+	copyFile := func(ctx android.SingletonContext, path android.Path, out string, fake bool) android.OutputPath {
+		if fake {
+			// All prebuilt binaries and headers are installed by copyFile function. This makes a fake
+			// snapshot just touch prebuilts and headers, rather than installing real files.
 			return writeStringToFileRule(ctx, "", out)
+		} else {
+			return copyFileRule(ctx, path, out)
 		}
 	}
 
 	// installSnapshot function copies prebuilt file (.so, .a, or executable) and json flag file.
 	// For executables, init_rc and vintf_fragments files are also copied.
-	installSnapshot := func(m *Module) android.Paths {
+	installSnapshot := func(m *Module, fake bool) android.Paths {
 		targetArch := "arch-" + m.Target().Arch.ArchType.String()
 		if m.Target().Arch.ArchVariant != "" {
 			targetArch += "-" + m.Target().Arch.ArchVariant
@@ -419,7 +416,7 @@
 			out := filepath.Join(configsDir, path.Base())
 			if !installedConfigs[out] {
 				installedConfigs[out] = true
-				ret = append(ret, copyFile(ctx, path, out))
+				ret = append(ret, copyFile(ctx, path, out, fake))
 			}
 		}
 
@@ -470,7 +467,7 @@
 					prop.ModuleName += ".cfi"
 				}
 				snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
-				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut, fake))
 			} else {
 				stem = ctx.ModuleName(m)
 			}
@@ -484,7 +481,7 @@
 			// install bin
 			binPath := m.outputFile.Path()
 			snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
-			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut))
+			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut, fake))
 			propOut = snapshotBinOut + ".json"
 		} else if m.object() {
 			// object files aren't installed to the device, so their names can conflict.
@@ -492,7 +489,7 @@
 			objPath := m.outputFile.Path()
 			snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
 				ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
-			ret = append(ret, copyFile(ctx, objPath, snapshotObjOut))
+			ret = append(ret, copyFile(ctx, objPath, snapshotObjOut, fake))
 			propOut = snapshotObjOut + ".json"
 		} else {
 			ctx.Errorf("unknown module %q in vendor snapshot", m.String())
@@ -532,9 +529,17 @@
 			return
 		}
 
-		// installSnapshot installs prebuilts and json flag files
-		snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...)
+		// If we are using directed snapshot and a module is not included in the
+		// list, we will still include the module as if it was a fake module.
+		// The reason is that soong needs all the dependencies to be present, even
+		// if they are not using during the build.
+		installAsFake := c.fake
+		if c.image.excludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) {
+			installAsFake = true
+		}
 
+		// installSnapshot installs prebuilts and json flag files
+		snapshotOutputs = append(snapshotOutputs, installSnapshot(m, installAsFake)...)
 		// just gather headers and notice files here, because they are to be deduplicated
 		if l, ok := m.linker.(snapshotLibraryInterface); ok {
 			headers = append(headers, l.snapshotHeaders()...)
@@ -553,7 +558,7 @@
 
 	// install all headers after removing duplicates
 	for _, header := range android.FirstUniquePaths(headers) {
-		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String())))
+		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), c.fake))
 	}
 
 	// All artifacts are ready. Sort them to normalize ninja and then zip.
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 499d7ae..659b693 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -228,7 +228,6 @@
 	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
 
 	var includeJsonFiles []string
-	var excludeJsonFiles []string
 
 	for _, arch := range [][]string{
 		[]string{"arm64", "armv8-a"},
@@ -248,9 +247,10 @@
 		checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
 		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
 
-		// Excluded modules
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor_available.so.json"))
+		// Excluded modules. Modules not included in the directed vendor snapshot
+		// are still include as fake modules.
+		checkSnapshotRule(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor_available.so.json"))
 	}
 
 	// Verify that each json file for an included module has a rule.
@@ -259,13 +259,6 @@
 			t.Errorf("include json file %q not found", jsonFile)
 		}
 	}
-
-	// Verify that each json file for an excluded module has no rule.
-	for _, jsonFile := range excludeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
-			t.Errorf("exclude json file %q found", jsonFile)
-		}
-	}
 }
 
 func TestVendorSnapshotUse(t *testing.T) {