Implement directed recovery snapshot.

Bug: 177451657
Test: m -j nothing
Change-Id: I0b84c34fb2e9e9340d9f9e7405428cd2cc4d43b5
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index b82628c..62daafd 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -195,8 +195,12 @@
 }
 
 func (recoverySnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool {
-	// directed recovery snapshot is not implemented yet
-	return false
+	// If we're using full snapshot, not directed snapshot, capture every module
+	if !cfg.DirectedRecoverySnapshot() {
+		return false
+	}
+	// Else, checks if name is in RECOVERY_SNAPSHOT_MODULES.
+	return !cfg.RecoverySnapshotModules()[name]
 }
 
 func (recoverySnapshotImage) imageVariantName(cfg android.DeviceConfig) string {
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 659b693..7e283fb 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -1051,3 +1051,85 @@
 		}
 	}
 }
+
+func TestRecoverySnapshotDirected(t *testing.T) {
+	bp := `
+	cc_library_shared {
+		name: "librecovery",
+		recovery: true,
+		nocrt: true,
+	}
+
+	cc_library_shared {
+		name: "librecovery_available",
+		recovery_available: true,
+		nocrt: true,
+	}
+
+	genrule {
+		name: "libfoo_gen",
+		cmd: "",
+		out: ["libfoo.so"],
+	}
+
+	cc_prebuilt_library_shared {
+		name: "libfoo",
+		recovery: true,
+		prefer: true,
+		srcs: [":libfoo_gen"],
+	}
+
+	cc_library_shared {
+		name: "libfoo",
+		recovery: true,
+		nocrt: true,
+	}
+`
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.DirectedRecoverySnapshot = true
+	config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
+	config.TestProductVariables.RecoverySnapshotModules["librecovery"] = true
+	config.TestProductVariables.RecoverySnapshotModules["libfoo"] = true
+	ctx := testCcWithConfig(t, config)
+
+	// Check recovery snapshot output.
+
+	snapshotDir := "recovery-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+	var includeJsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+
+		// Included modules
+		checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
+		// Check that snapshot captures "prefer: true" prebuilt
+		checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
+
+		// Excluded modules. Modules not included in the directed recovery snapshot
+		// are still include as fake modules.
+		checkSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json"))
+	}
+
+	// Verify that each json file for an included module has a rule.
+	for _, jsonFile := range includeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("include json file %q not found", jsonFile)
+		}
+	}
+}