Merge "Instrument ims-common for coverage"
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index c157d39..1f87410 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -142,7 +142,7 @@
 	GetPythonBinary(label string, cfgKey configKey) (string, error)
 
 	// Returns the results of the GetApexInfo query (including output files)
-	GetApexInfo(label string, cfgkey configKey) (cquery.ApexCqueryInfo, error)
+	GetApexInfo(label string, cfgkey configKey) (cquery.ApexInfo, error)
 
 	// Returns the results of the GetCcUnstrippedInfo query
 	GetCcUnstrippedInfo(label string, cfgkey configKey) (cquery.CcUnstrippedInfo, error)
@@ -226,7 +226,7 @@
 	LabelToOutputFiles  map[string][]string
 	LabelToCcInfo       map[string]cquery.CcInfo
 	LabelToPythonBinary map[string]string
-	LabelToApexInfo     map[string]cquery.ApexCqueryInfo
+	LabelToApexInfo     map[string]cquery.ApexInfo
 	LabelToCcBinary     map[string]cquery.CcUnstrippedInfo
 }
 
@@ -249,7 +249,7 @@
 	return result, nil
 }
 
-func (n MockBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
+func (m MockBazelContext) GetApexInfo(label string, _ configKey) (cquery.ApexInfo, error) {
 	panic("unimplemented")
 }
 
@@ -313,12 +313,12 @@
 	return "", fmt.Errorf("no bazel response found for %v", key)
 }
 
-func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexCqueryInfo, error) {
+func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquery.ApexInfo, error) {
 	key := makeCqueryKey(label, cquery.GetApexInfo, cfgKey)
 	if rawString, ok := bazelCtx.results[key]; ok {
 		return cquery.GetApexInfo.ParseResult(strings.TrimSpace(rawString)), nil
 	}
-	return cquery.ApexCqueryInfo{}, fmt.Errorf("no bazel response found for %v", key)
+	return cquery.ApexInfo{}, fmt.Errorf("no bazel response found for %v", key)
 }
 
 func (bazelCtx *bazelContext) GetCcUnstrippedInfo(label string, cfgKey configKey) (cquery.CcUnstrippedInfo, error) {
@@ -345,7 +345,7 @@
 	panic("unimplemented")
 }
 
-func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryInfo, error) {
+func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexInfo, error) {
 	panic("unimplemented")
 }
 
diff --git a/android/metrics.go b/android/metrics.go
index ecda026..3d41a1d 100644
--- a/android/metrics.go
+++ b/android/metrics.go
@@ -62,7 +62,7 @@
 	})
 }
 
-func collectMetrics(config Config, eventHandler metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics {
+func collectMetrics(config Config, eventHandler *metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics {
 	metrics := &soong_metrics_proto.SoongBuildMetrics{}
 
 	soongMetrics, ok := readSoongMetrics(config)
@@ -107,7 +107,7 @@
 	return metrics
 }
 
-func WriteMetrics(config Config, eventHandler metrics.EventHandler, metricsFile string) error {
+func WriteMetrics(config Config, eventHandler *metrics.EventHandler, metricsFile string) error {
 	metrics := collectMetrics(config, eventHandler)
 
 	buf, err := proto.Marshal(metrics)
diff --git a/android/testing.go b/android/testing.go
index f9f9670..2256c96 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -1120,6 +1120,7 @@
 }
 
 func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) []AndroidMkEntries {
+	t.Helper()
 	var p AndroidMkEntriesProvider
 	var ok bool
 	if p, ok = mod.(AndroidMkEntriesProvider); !ok {
@@ -1134,6 +1135,7 @@
 }
 
 func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) AndroidMkData {
+	t.Helper()
 	var p AndroidMkDataProvider
 	var ok bool
 	if p, ok = mod.(AndroidMkDataProvider); !ok {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 21a71ce..10adf8d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -16,7 +16,6 @@
 
 import (
 	"fmt"
-	"os"
 	"path"
 	"path/filepath"
 	"reflect"
@@ -9745,7 +9744,3 @@
 	libcCoreVariant := result.ModuleForTests("libc.apiimport", "android_arm64_armv8-a_shared").Module()
 	android.AssertBoolEquals(t, "core variant should link against source libc", true, hasDep(libfooCoreVariant, libcCoreVariant))
 }
-
-func TestMain(m *testing.M) {
-	os.Exit(m.Run())
-}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index febca5d..f624bf8 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -221,7 +221,7 @@
 })`
 }
 
-type ApexCqueryInfo struct {
+type ApexInfo struct {
 	SignedOutput     string   `json:"signed_output"`
 	UnsignedOutput   string   `json:"unsigned_output"`
 	ProvidesLibs     []string `json:"provides_native_libs"`
@@ -234,8 +234,8 @@
 // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
 // The given rawString must correspond to the string output which was created by evaluating the
 // Starlark given in StarlarkFunctionBody.
-func (g getApexInfoType) ParseResult(rawString string) ApexCqueryInfo {
-	var info ApexCqueryInfo
+func (g getApexInfoType) ParseResult(rawString string) ApexInfo {
+	var info ApexInfo
 	parseJson(rawString, &info)
 	return info
 }
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 42b42e1..09e3885 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -133,12 +133,12 @@
 	testCases := []struct {
 		description    string
 		input          string
-		expectedOutput ApexCqueryInfo
+		expectedOutput ApexInfo
 	}{
 		{
 			description:    "no result",
 			input:          "{}",
-			expectedOutput: ApexCqueryInfo{},
+			expectedOutput: ApexInfo{},
 		},
 		{
 			description: "one result",
@@ -149,7 +149,7 @@
 				`"container_key_info":["foo.x509.pem", "foo.pk8", "foo"],` +
 				`"package_name":"package.name",` +
 				`"provides_native_libs":[]}`,
-			expectedOutput: ApexCqueryInfo{
+			expectedOutput: ApexInfo{
 				SignedOutput:     "my.apex",
 				UnsignedOutput:   "my.apex.unsigned",
 				RequiresLibs:     []string{"//bionic/libc:libc", "//bionic/libdl:libdl"},
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index a06b89e..5ab54e3 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -136,7 +136,7 @@
 
 type CodegenContext struct {
 	config             android.Config
-	context            android.Context
+	context            *android.Context
 	mode               CodegenMode
 	additionalDeps     []string
 	unconvertedDepMode unconvertedDepsMode
@@ -203,12 +203,12 @@
 	return ctx.additionalDeps
 }
 
-func (ctx *CodegenContext) Config() android.Config   { return ctx.config }
-func (ctx *CodegenContext) Context() android.Context { return ctx.context }
+func (ctx *CodegenContext) Config() android.Config    { return ctx.config }
+func (ctx *CodegenContext) Context() *android.Context { return ctx.context }
 
 // NewCodegenContext creates a wrapper context that conforms to PathContext for
 // writing BUILD files in the output directory.
-func NewCodegenContext(config android.Config, context android.Context, mode CodegenMode) *CodegenContext {
+func NewCodegenContext(config android.Config, context *android.Context, mode CodegenMode) *CodegenContext {
 	var unconvertedDeps unconvertedDepsMode
 	if config.IsEnvTrue("BP2BUILD_ERROR_UNCONVERTED") {
 		unconvertedDeps = errorModulesUnconvertedDeps
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index 7c24a94..c40c45a 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -209,7 +209,7 @@
 			_, errs = ctx.PrepareBuildActions(config)
 			android.FailIfErrored(t, errs)
 
-			codegenCtx := NewCodegenContext(config, *ctx.Context, QueryView)
+			codegenCtx := NewCodegenContext(config, ctx.Context, QueryView)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 			if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
@@ -530,7 +530,7 @@
 				return
 			}
 
-			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 
@@ -903,7 +903,7 @@
 		_, errs = ctx.ResolveDependencies(config)
 		android.FailIfErrored(t, errs)
 
-		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 		bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 		android.FailIfErrored(t, err)
 		if actualCount := len(bazelTargets); actualCount != testCase.expectedBazelTargetCount {
@@ -1156,7 +1156,7 @@
 			_, errs = ctx.ResolveDependencies(config)
 			android.FailIfErrored(t, errs)
 
-			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, dir)
 			android.FailIfErrored(t, err)
 			if actualCount := len(bazelTargets); actualCount != testCase.expectedCount {
@@ -1263,7 +1263,7 @@
 		_, errs = ctx.ResolveDependencies(config)
 		android.FailIfErrored(t, errs)
 
-		codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+		codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 
 		// For each directory, test that the expected number of generated targets is correct.
 		for dir, expectedCount := range testCase.expectedCount {
@@ -1398,7 +1398,7 @@
 			if testCase.Dir != "" {
 				checkDir = testCase.Dir
 			}
-			codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+			codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 			bazelTargets, err := generateBazelTargetsForDir(codegenCtx, checkDir)
 			android.FailIfErrored(t, err)
 			bazelTargets.sort()
diff --git a/bp2build/performance_test.go b/bp2build/performance_test.go
index c4bbae2..272ebf5 100644
--- a/bp2build/performance_test.go
+++ b/bp2build/performance_test.go
@@ -22,11 +22,12 @@
 // run for longer, set -benchtime to a larger value.
 
 import (
-	"android/soong/android"
 	"fmt"
 	"math"
 	"strings"
 	"testing"
+
+	"android/soong/android"
 )
 
 const (
@@ -105,7 +106,7 @@
 	ctx := android.NewTestContext(config)
 
 	registerCustomModuleForBp2buildConversion(ctx)
-	codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 	return testConfig{
 		config,
 		ctx,
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 31aa830..3750804 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -155,7 +155,7 @@
 	if tc.Dir != "" {
 		checkDir = tc.Dir
 	}
-	codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+	codegenCtx := NewCodegenContext(config, ctx.Context, Bp2Build)
 	codegenCtx.unconvertedDepMode = tc.UnconvertedDepsMode
 	bazelTargets, errs := generateBazelTargetsForDir(codegenCtx, checkDir)
 	if tc.ExpectedErr != nil {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 0669f65..3fed1a1 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -187,14 +187,14 @@
 	globListFiles := writeBuildGlobsNinjaFile(ctx, configuration.SoongOutDir(), configuration)
 	ninjaDeps = append(ninjaDeps, globListFiles...)
 
-	writeDepFile(cmdlineArgs.OutFile, *ctx.EventHandler, ninjaDeps)
+	writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
 }
 
 // Run the code-generation phase to convert BazelTargetModules to BUILD files.
 func runQueryView(queryviewDir, queryviewMarker string, configuration android.Config, ctx *android.Context) {
 	ctx.EventHandler.Begin("queryview")
 	defer ctx.EventHandler.End("queryview")
-	codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView)
+	codegenContext := bp2build.NewCodegenContext(configuration, ctx, bp2build.QueryView)
 	absoluteQueryViewDir := shared.JoinPath(topDir, queryviewDir)
 	if err := createBazelWorkspace(codegenContext, absoluteQueryViewDir); err != nil {
 		fmt.Fprintf(os.Stderr, "%s", err)
@@ -235,7 +235,7 @@
 	ninjaDeps = append(ninjaDeps, globs...)
 
 	// Run codegen to generate BUILD files
-	codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.ApiBp2build)
+	codegenContext := bp2build.NewCodegenContext(configuration, ctx, bp2build.ApiBp2build)
 	absoluteApiBp2buildDir := shared.JoinPath(topDir, bazelApiBp2buildDir)
 	if err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir); err != nil {
 		fmt.Fprintf(os.Stderr, "%s", err)
@@ -266,7 +266,7 @@
 	ninjaDeps = append(ninjaDeps, symlinkDeps...)
 
 	workspaceMarkerFile := workspace + ".marker"
-	writeDepFile(workspaceMarkerFile, *ctx.EventHandler, ninjaDeps)
+	writeDepFile(workspaceMarkerFile, ctx.EventHandler, ninjaDeps)
 	touch(shared.JoinPath(topDir, workspaceMarkerFile))
 	return workspaceMarkerFile
 }
@@ -293,7 +293,7 @@
 	return ret
 }
 
-func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler, metricsDir string) {
+func writeMetrics(configuration android.Config, eventHandler *metrics.EventHandler, metricsDir string) {
 	if len(metricsDir) < 1 {
 		fmt.Fprintf(os.Stderr, "\nMissing required env var for generating soong metrics: LOG_DIR\n")
 		os.Exit(1)
@@ -333,7 +333,7 @@
 	return bootstrap.GlobFileListFiles(globDir)
 }
 
-func writeDepFile(outputFile string, eventHandler metrics.EventHandler, ninjaDeps []string) {
+func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) {
 	eventHandler.Begin("ninja_deps")
 	defer eventHandler.End("ninja_deps")
 	depFile := shared.JoinPath(topDir, outputFile+".d")
@@ -347,14 +347,14 @@
 // doChosenActivity runs Soong for a specific activity, like bp2build, queryview
 // or the actual Soong build for the build.ninja file. Returns the top level
 // output file of the specific activity.
-func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string) string {
+func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string, metricsDir string) string {
 	if configuration.BuildMode == android.SymlinkForest {
-		runSymlinkForestCreation(configuration, extraNinjaDeps)
+		runSymlinkForestCreation(configuration, extraNinjaDeps, metricsDir)
 		return symlinkForestMarker
 	} else if configuration.BuildMode == android.Bp2build {
 		// Run the alternate pipeline of bp2build mutators and singleton to convert
 		// Blueprint to BUILD files before everything else.
-		runBp2Build(configuration, extraNinjaDeps)
+		runBp2Build(configuration, extraNinjaDeps, metricsDir)
 		return bp2buildMarker
 	} else if configuration.IsMixedBuildsEnabled() {
 		runMixedModeBuild(configuration, ctx, extraNinjaDeps)
@@ -380,11 +380,11 @@
 		if configuration.BuildMode == android.GenerateQueryView {
 			queryviewMarkerFile := bazelQueryViewDir + ".marker"
 			runQueryView(bazelQueryViewDir, queryviewMarkerFile, configuration, ctx)
-			writeDepFile(queryviewMarkerFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(queryviewMarkerFile, ctx.EventHandler, ninjaDeps)
 			return queryviewMarkerFile
 		} else if configuration.BuildMode == android.GenerateModuleGraph {
 			writeJsonModuleGraphAndActions(ctx, moduleGraphFile, moduleActionsFile)
-			writeDepFile(moduleGraphFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(moduleGraphFile, ctx.EventHandler, ninjaDeps)
 			return moduleGraphFile
 		} else if configuration.BuildMode == android.GenerateDocFile {
 			// TODO: we could make writeDocs() return the list of documentation files
@@ -394,12 +394,12 @@
 				fmt.Fprintf(os.Stderr, "error building Soong documentation: %s\n", err)
 				os.Exit(1)
 			}
-			writeDepFile(docFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(docFile, ctx.EventHandler, ninjaDeps)
 			return docFile
 		} else {
 			// The actual output (build.ninja) was written in the RunBlueprint() call
 			// above
-			writeDepFile(cmdlineArgs.OutFile, *ctx.EventHandler, ninjaDeps)
+			writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
 		}
 	}
 
@@ -465,10 +465,10 @@
 	ctx := newContext(configuration)
 	ctx.EventHandler.Begin("soong_build")
 
-	finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps)
+	finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps, logDir)
 
 	ctx.EventHandler.End("soong_build")
-	writeMetrics(configuration, *ctx.EventHandler, logDir)
+	writeMetrics(configuration, ctx.EventHandler, logDir)
 
 	writeUsedEnvironmentFile(configuration, finalOutputFile)
 }
@@ -614,8 +614,8 @@
 // Ideally, bp2build would write a file that contains instructions to the
 // symlink tree creation binary. Then the latter would not need to depend on
 // the very heavy-weight machinery of soong_build .
-func runSymlinkForestCreation(configuration android.Config, extraNinjaDeps []string) {
-	eventHandler := metrics.EventHandler{}
+func runSymlinkForestCreation(configuration android.Config, extraNinjaDeps []string, metricsDir string) {
+	eventHandler := &metrics.EventHandler{}
 
 	var ninjaDeps []string
 	ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
@@ -651,7 +651,6 @@
 
 	writeDepFile(symlinkForestMarker, eventHandler, ninjaDeps)
 	touch(shared.JoinPath(topDir, symlinkForestMarker))
-	metricsDir := configuration.Getenv("LOG_DIR")
 	codegenMetrics := bp2build.ReadCodegenMetrics(metricsDir)
 	if codegenMetrics == nil {
 		m := bp2build.CreateCodegenMetrics()
@@ -660,15 +659,15 @@
 		//TODO (usta) we cannot determine if we loaded a stale file, i.e. from an unrelated prior
 		//invocation of codegen. We should simply use a separate .pb file
 	}
-	writeBp2BuildMetrics(codegenMetrics, configuration, eventHandler)
+	writeBp2BuildMetrics(codegenMetrics, eventHandler, metricsDir)
 }
 
 // Run Soong in the bp2build mode. This creates a standalone context that registers
 // an alternate pipeline of mutators and singletons specifically for generating
 // Bazel BUILD files instead of Ninja files.
-func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
+func runBp2Build(configuration android.Config, extraNinjaDeps []string, metricsDir string) {
 	var codegenMetrics *bp2build.CodegenMetrics
-	eventHandler := metrics.EventHandler{}
+	eventHandler := &metrics.EventHandler{}
 	eventHandler.Do("bp2build", func() {
 
 		// Register an alternate set of singletons and mutators for bazel
@@ -699,7 +698,7 @@
 
 		// Run the code-generation phase to convert BazelTargetModules to BUILD files
 		// and print conversion codegenMetrics to the user.
-		codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
+		codegenContext := bp2build.NewCodegenContext(configuration, bp2buildCtx, bp2build.Bp2Build)
 		eventHandler.Do("codegen", func() {
 			codegenMetrics = bp2build.Codegen(codegenContext)
 		})
@@ -716,12 +715,11 @@
 	if configuration.IsEnvTrue("BP2BUILD_VERBOSE") {
 		codegenMetrics.Print()
 	}
-	writeBp2BuildMetrics(codegenMetrics, configuration, eventHandler)
+	writeBp2BuildMetrics(codegenMetrics, eventHandler, metricsDir)
 }
 
 // Write Bp2Build metrics into $LOG_DIR
-func writeBp2BuildMetrics(codegenMetrics *bp2build.CodegenMetrics,
-	configuration android.Config, eventHandler metrics.EventHandler) {
+func writeBp2BuildMetrics(codegenMetrics *bp2build.CodegenMetrics, eventHandler *metrics.EventHandler, metricsDir string) {
 	for _, event := range eventHandler.CompletedEvents() {
 		codegenMetrics.AddEvent(&bp2build_metrics_proto.Event{
 			Name:      event.Id,
@@ -729,7 +727,6 @@
 			RealTime:  event.RuntimeNanoseconds(),
 		})
 	}
-	metricsDir := configuration.Getenv("LOG_DIR")
 	if len(metricsDir) < 1 {
 		fmt.Fprintf(os.Stderr, "\nMissing required env var for generating bp2build metrics: LOG_DIR\n")
 		os.Exit(1)
diff --git a/scripts/gen_ndk_usedby_apex.sh b/scripts/gen_ndk_usedby_apex.sh
index 0d3ed5a..93d1370 100755
--- a/scripts/gen_ndk_usedby_apex.sh
+++ b/scripts/gen_ndk_usedby_apex.sh
@@ -19,6 +19,7 @@
 # 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."
@@ -29,30 +30,33 @@
 }
 
 parseReadelfOutput() {
+  local readelfOutput=$1; shift
+  local ndkApisOutput=$1; shift
   while IFS= read -r line
   do
       if [[ $line = *FUNC*GLOBAL*UND*@* ]] ;
       then
-          echo "$line" | sed -r 's/.*UND (.*@.*)/\1/g' >> "$2"
+          echo "$line" | sed -r 's/.*UND (.*@.*)/\1/g' >> "${ndkApisOutput}"
       fi
-  done < "$1"
-  echo "" >> "$2"
+  done < "${readelfOutput}"
+  echo "" >> "${ndkApisOutput}"
 }
 
 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 {} \;
+  local dir="$1"; shift
+  local tmpUnzippedDir="$1"; shift
+  mkdir -p "${tmpUnzippedDir}"
+  find "$dir" -name "*.jar" -exec unzip -o {} -d "${tmpUnzippedDir}" \;
+  find "$dir" -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 \;
+  local dir="$1"; shift
+  local readelf="$1"; shift
+  local tmpOutput="$1"; shift
+  find -L "$dir" -type f -name "*.so"  -exec "${readelf}" --dyn-symbols {} >> "${tmpOutput}" \;
+  find -L "$dir" -type f -perm /111 ! -name "*.so" -exec "${readelf}" --dyn-symbols {} >> "${tmpOutput}" \;
 }
 
 if [[ "$1" == "help" ]]
@@ -62,11 +66,22 @@
 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
+  imageDir="$1"; shift
+  readelf="$1"; shift
+  outputFile="$1"; shift
+
+  tmpReadelfOutput=$(mktemp /tmp/temporary-file.XXXXXXXX)
+  tmpUnzippedDir=$(mktemp -d /tmp/temporary-dir.XXXXXXXX)
+  trap 'rm -rf -- "${tmpReadelfOutput}" "${tmpUnzippedDir}"' EXIT
+
+  # If there are any jars or apks, unzip them to surface native files.
+  unzipJarAndApk "${imageDir}" "${tmpUnzippedDir}"
+  # Analyze the unzipped files.
+  lookForExecFile "${tmpUnzippedDir}" "${readelf}" "${tmpReadelfOutput}"
+
+  # Analyze the apex image staging dir itself.
+  lookForExecFile "${imageDir}" "${readelf}" "${tmpReadelfOutput}"
+
+  [[ -e "${outputFile}" ]] && rm "${outputFile}"
+  parseReadelfOutput "${tmpReadelfOutput}" "${outputFile}"
+fi