Put dependency in apex_manifest.json

To generate ld.config.txt dynamically(b/123722631), each APEX should
provide some dependency information:
a) list of libraries which other APEXes(or system) can use from this apex
b) list of libraries which this apex uses from other APEXes(or system)

This change puts dependency information in apex_manifest.json at
build-time with two additional keys:
a) provideNativeLibs
b) requireNativeLibs

Bug: 138695532
Test: m (runs soong tests)
Test: find $OUT/apex -name apex_manifest.json  -exec cat {} \;
 (shows contents of apex_manifest.json files)

Change-Id: Iaad12c8c35454222ad177ce923cce76ef12a8a5a
diff --git a/apex/apex.go b/apex/apex.go
index 441911b..5ca9d7d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -46,6 +46,14 @@
 		Description: "fs_config ${out}",
 	}, "ro_paths", "exec_paths")
 
+	injectApexDependency = pctx.StaticRule("injectApexDependency", blueprint.RuleParams{
+		Command: `rm -f $out && ${jsonmodify} $in ` +
+			`-a provideNativeLibs ${provideNativeLibs} ` +
+			`-a requireNativeLibs ${requireNativeLibs} -o $out`,
+		CommandDeps: []string{"${jsonmodify}"},
+		Description: "Inject dependency into ${out}",
+	}, "provideNativeLibs", "requireNativeLibs")
+
 	// TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
 	// against the binary policy using sefcontext_compiler -p <policy>.
 
@@ -139,6 +147,7 @@
 	pctx.HostBinToolVariable("soong_zip", "soong_zip")
 	pctx.HostBinToolVariable("zip2zip", "zip2zip")
 	pctx.HostBinToolVariable("zipalign", "zipalign")
+	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
 
 	android.RegisterModuleType("apex", apexBundleFactory)
 	android.RegisterModuleType("apex_test", testApexBundleFactory)
@@ -427,6 +436,9 @@
 	flattened bool
 
 	testApex bool
+
+	// intermediate path for apex_manifest.json
+	manifestOut android.WritablePath
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -751,6 +763,10 @@
 
 	handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
 
+	// native lib dependencies
+	var provideNativeLibs []string
+	var requireNativeLibs []string
+
 	// Check if "uses" requirements are met with dependent apexBundles
 	var providedNativeSharedLibs []string
 	useVendor := proptools.Bool(a.properties.Use_vendor)
@@ -783,6 +799,9 @@
 			switch depTag {
 			case sharedLibTag:
 				if cc, ok := child.(*cc.Module); ok {
+					if cc.HasStubsVariants() {
+						provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
+					}
 					fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
 					filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
 					return true
@@ -894,6 +913,7 @@
 							if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
 								a.externalDeps = append(a.externalDeps, cc.Name())
 							}
+							requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
 							// Don't track further
 							return false
 						}
@@ -954,6 +974,21 @@
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = filesInfo
 
+	a.manifestOut = android.PathForModuleOut(ctx, "apex_manifest.json")
+	// put dependency({provide|require}NativeLibs) in apex_manifest.json
+	manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
+	provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
+	requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   injectApexDependency,
+		Input:  manifestSrc,
+		Output: a.manifestOut,
+		Args: map[string]string{
+			"provideNativeLibs": strings.Join(provideNativeLibs, " "),
+			"requireNativeLibs": strings.Join(requireNativeLibs, " "),
+		},
+	})
+
 	if a.apexTypes.zip() {
 		a.buildUnflattenedApex(ctx, zipApex)
 	}
@@ -1001,8 +1036,6 @@
 		a.container_private_key_file = key
 	}
 
-	manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-
 	var abis []string
 	for _, target := range ctx.MultiTargets() {
 		if len(target.Arch.Abi) > 0 {
@@ -1032,7 +1065,7 @@
 		}
 	}
 	implicitInputs := append(android.Paths(nil), filesToCopy...)
-	implicitInputs = append(implicitInputs, manifest)
+	implicitInputs = append(implicitInputs, a.manifestOut)
 
 	outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
 	prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
@@ -1127,7 +1160,7 @@
 				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
 				"image_dir":        android.PathForModuleOut(ctx, "image"+suffix).String(),
 				"copy_commands":    strings.Join(copyCommands, " && "),
-				"manifest":         manifest.String(),
+				"manifest":         a.manifestOut.String(),
 				"file_contexts":    fileContexts.String(),
 				"canned_fs_config": cannedFsConfig.String(),
 				"key":              a.private_key_file.String(),
@@ -1165,7 +1198,7 @@
 				"tool_path":     outHostBinDir + ":" + prebuiltSdkToolsBinDir,
 				"image_dir":     android.PathForModuleOut(ctx, "image"+suffix).String(),
 				"copy_commands": strings.Join(copyCommands, " && "),
-				"manifest":      manifest.String(),
+				"manifest":      a.manifestOut.String(),
 			},
 		})
 	}
@@ -1196,16 +1229,7 @@
 	if a.installable() {
 		// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
 		// with other ordinary files.
-		manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-
-		// rename to apex_manifest.json
-		copiedManifest := android.PathForModuleOut(ctx, "apex_manifest.json")
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   android.Cp,
-			Input:  manifest,
-			Output: copiedManifest,
-		})
-		a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
 
 		// rename to apex_pubkey
 		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")