Support boringssl hash injection on binaries and make it transitive

Move handling the inject_bssl_hash property to a helper function,
and also treat it as set if any static libraries have it set.

Bug: 137267623
Test: m checkbuild
Change-Id: Icb12cfffb20797c807b410daffbf7fcccb1b1975
diff --git a/cc/binary.go b/cc/binary.go
index fd00060..17e729c 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -50,6 +50,9 @@
 	// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
 	// from PRODUCT_PACKAGES.
 	Overrides []string
+
+	// Inject boringssl hash into the shared library.  This is only intended for use by external/boringssl.
+	Inject_bssl_hash *bool `android:"arch_variant"`
 }
 
 func init() {
@@ -342,6 +345,8 @@
 			flagsToBuilderFlags(flags), afterPrefixSymbols)
 	}
 
+	outputFile = maybeInjectBoringSSLHash(ctx, outputFile, binary.Properties.Inject_bssl_hash, fileName)
+
 	if Bool(binary.baseLinker.Properties.Use_version_lib) {
 		if ctx.Host() {
 			versionedOutputFile := outputFile
diff --git a/cc/library.go b/cc/library.go
index 52fd346..9178a52 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -771,18 +771,7 @@
 	}
 	library.unstrippedOutputFile = outputFile
 
-	// TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries.
-	if Bool(library.Properties.Inject_bssl_hash) {
-		hashedOutputfile := outputFile
-		outputFile = android.PathForModuleOut(ctx, "unhashed", fileName)
-
-		rule := android.NewRuleBuilder()
-		rule.Command().
-			BuiltTool(ctx, "bssl_inject_hash").
-			FlagWithInput("-in-object ", outputFile).
-			FlagWithOutput("-o ", hashedOutputfile)
-		rule.Build(pctx, ctx, "injectCryptoHash", "inject crypto hash")
-	}
+	outputFile = maybeInjectBoringSSLHash(ctx, outputFile, library.Properties.Inject_bssl_hash, fileName)
 
 	if Bool(library.baseLinker.Properties.Use_version_lib) {
 		if ctx.Host() {
@@ -1296,3 +1285,38 @@
 		}
 	}
 }
+
+// maybeInjectBoringSSLHash adds a rule to run bssl_inject_hash on the output file if the module has the
+// inject_bssl_hash or if any static library dependencies have inject_bssl_hash set.  It returns the output path
+// that the linked output file should be written to.
+// TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries.
+func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.ModuleOutPath,
+	inject *bool, fileName string) android.ModuleOutPath {
+	// TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries.
+	injectBoringSSLHash := Bool(inject)
+	ctx.VisitDirectDeps(func(dep android.Module) {
+		tag := ctx.OtherModuleDependencyTag(dep)
+		if tag == staticDepTag || tag == staticExportDepTag || tag == wholeStaticDepTag || tag == lateStaticDepTag {
+			if cc, ok := dep.(*Module); ok {
+				if library, ok := cc.linker.(*libraryDecorator); ok {
+					if Bool(library.Properties.Inject_bssl_hash) {
+						injectBoringSSLHash = true
+					}
+				}
+			}
+		}
+	})
+	if injectBoringSSLHash {
+		hashedOutputfile := outputFile
+		outputFile = android.PathForModuleOut(ctx, "unhashed", fileName)
+
+		rule := android.NewRuleBuilder()
+		rule.Command().
+			BuiltTool(ctx, "bssl_inject_hash").
+			FlagWithInput("-in-object ", outputFile).
+			FlagWithOutput("-o ", hashedOutputfile)
+		rule.Build(pctx, ctx, "injectCryptoHash", "inject crypto hash")
+	}
+
+	return outputFile
+}