Merge "Cherrypick from: https://android-review.googlesource.com/c/platform/build/soong/+/1463105" into mainline-prod
diff --git a/apex/apex.go b/apex/apex.go
index 927aa0b..dab515d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1399,6 +1399,9 @@
 
 	// Optional list of lint report zip files for apexes that contain java or app modules
 	lintReports android.Paths
+
+	// Path of API coverage generate file
+	coverageOutputPath android.ModuleOutPath
 }
 
 func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
diff --git a/apex/builder.go b/apex/builder.go
index 78866db..a75252f 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -36,6 +36,7 @@
 
 func init() {
 	pctx.Import("android/soong/android")
+	pctx.Import("android/soong/cc/config")
 	pctx.Import("android/soong/java")
 	pctx.HostBinToolVariable("apexer", "apexer")
 	// ART minimal builds (using the master-art manifest) do not have the "frameworks/base"
@@ -62,6 +63,7 @@
 	pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
 	pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest")
 	pctx.HostBinToolVariable("extract_apks", "extract_apks")
+	pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh")
 }
 
 var (
@@ -172,6 +174,12 @@
 			`exit 1); touch ${out}`,
 		Description: "Diff ${image_content_file} and ${allowed_files_file}",
 	}, "image_content_file", "allowed_files_file", "apex_module_name")
+
+	generateAPIsUsedbyApexRule = pctx.StaticRule("generateAPIsUsedbyApexRule", blueprint.RuleParams{
+		Command:     "$genNdkUsedbyApexPath ${image_dir} ${readelf} ${out}",
+		CommandDeps: []string{"${genNdkUsedbyApexPath}"},
+		Description: "Generate symbol list used by Apex",
+	}, "image_dir", "readelf")
 )
 
 func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) {
@@ -550,6 +558,22 @@
 			Description: "apex proto convert",
 		})
 
+		implicitInputs = append(implicitInputs, unsignedOutputFile)
+
+		// Run coverage analysis
+		apisUsedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+".txt")
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        generateAPIsUsedbyApexRule,
+			Implicits:   implicitInputs,
+			Description: "coverage",
+			Output:      apisUsedbyOutputFile,
+			Args: map[string]string{
+				"image_dir": imageDir.String(),
+				"readelf":   "${config.ClangBin}/llvm-readelf",
+			},
+		})
+		a.coverageOutputPath = apisUsedbyOutputFile
+
 		bundleConfig := a.buildBundleConfig(ctx)
 
 		ctx.Build(pctx, android.BuildParams{
diff --git a/scripts/gen_ndk_usedby_apex.sh b/scripts/gen_ndk_usedby_apex.sh
new file mode 100755
index 0000000..f143161
--- /dev/null
+++ b/scripts/gen_ndk_usedby_apex.sh
@@ -0,0 +1,72 @@
+#!/bin/bash -e
+
+# 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.
+
+# Generates NDK API txt file used by Mainline modules. NDK APIs would have value
+# "UND" in Ndx column and have suffix "@LIB_NAME" in Name column.
+# For example, current line llvm-readelf output is:
+# 1: 00000000     0     FUNC      GLOBAL  DEFAULT   UND   dlopen@LIBC
+# After the parse function below "dlopen" would be write to the output file.
+printHelp() {
+    echo "**************************** Usage Instructions ****************************"
+    echo "This script is used to generate the Mainline modules used-by NDK symbols."
+    echo ""
+    echo "To run this script use: ./ndk_usedby_module.sh \$BINARY_IMAGE_DIRECTORY \$BINARY_LLVM_PATH \$OUTPUT_FILE_PATH"
+    echo "For example: If all the module image files that you would like to run is under directory '/myModule' and output write to /myModule.txt then the command would be:"
+    echo "./ndk_usedby_module.sh /myModule \$BINARY_LLVM_PATH /myModule.txt"
+}
+
+parseReadelfOutput() {
+  while IFS= read -r line
+  do
+      if [[ $line = *FUNC*GLOBAL*UND*@* ]] ;
+      then
+          echo "$line" | sed -r 's/.*UND (.*)@.*/\1/g' >> "$2"
+      fi
+  done < "$1"
+  echo "" >> "$2"
+}
+
+unzipJarAndApk() {
+  tmpUnzippedDir="$1"/tmpUnzipped
+  [[ -e "$tmpUnzippedDir" ]] && rm -rf "$tmpUnzippedDir"
+  mkdir -p "$tmpUnzippedDir"
+  find "$1" -name "*.jar" -exec unzip -o {} -d "$tmpUnzippedDir" \;
+  find "$1" -name "*.apk" -exec unzip -o {} -d "$tmpUnzippedDir" \;
+  find "$tmpUnzippedDir" -name "*.MF" -exec rm {} \;
+}
+
+lookForExecFile() {
+  dir="$1"
+  readelf="$2"
+  find "$dir" -type f -name "*.so"  -exec "$2" --dyn-symbols {} >> "$dir"/../tmpReadelf.txt \;
+  find "$dir" -type f -perm /111 ! -name "*.so"  -exec "$2" --dyn-symbols {} >> "$dir"/../tmpReadelf.txt \;
+}
+
+if [[ "$1" == "help" ]]
+then
+  printHelp
+elif [[ "$#" -ne 3 ]]
+then
+  echo "Wrong argument length. Expecting 3 argument representing image file directory, llvm-readelf tool path, output path."
+else
+  unzipJarAndApk "$1"
+  lookForExecFile "$1" "$2"
+  tmpReadelfOutput="$1/../tmpReadelf.txt"
+  [[ -e "$3" ]] && rm "$3"
+  parseReadelfOutput "$tmpReadelfOutput" "$3"
+  [[ -e "$tmpReadelfOutput" ]] && rm "$tmpReadelfOutput"
+  rm -rf "$1/tmpUnzipped"
+fi
\ No newline at end of file