Merge "Add cc_library_headers support to bp2build."
diff --git a/android/config.go b/android/config.go
index 50e39d7..9162eaa 100644
--- a/android/config.go
+++ b/android/config.go
@@ -24,6 +24,7 @@
 	"os"
 	"path/filepath"
 	"runtime"
+	"strconv"
 	"strings"
 	"sync"
 
@@ -246,6 +247,7 @@
 			AAPTCharacteristics:               stringPtr("nosdcard"),
 			AAPTPrebuiltDPI:                   []string{"xhdpi", "xxhdpi"},
 			UncompressPrivAppDex:              boolPtr(true),
+			ShippingApiLevel:                  stringPtr("30"),
 		},
 
 		buildDir:     buildDir,
@@ -1421,6 +1423,18 @@
 	return c.config.productVariables.RecoverySnapshotModules
 }
 
+func (c *deviceConfig) ShippingApiLevel() ApiLevel {
+	if c.config.productVariables.ShippingApiLevel == nil {
+		return NoneApiLevel
+	}
+	apiLevel, _ := strconv.Atoi(*c.config.productVariables.ShippingApiLevel)
+	return uncheckedFinalApiLevel(apiLevel)
+}
+
+func (c *deviceConfig) BuildBrokenVendorPropertyNamespace() bool {
+	return c.config.productVariables.BuildBrokenVendorPropertyNamespace
+}
+
 // The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
 // Such lists are used in the build system for things like bootclasspath jars or system server jars.
 // The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
diff --git a/android/paths.go b/android/paths.go
index c3fa61a..58e1f74 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -280,7 +280,8 @@
 	return false
 }
 
-// PathsForSource returns Paths rooted from SrcDir
+// PathsForSource returns Paths rooted from SrcDir, *not* rooted from the module's local source
+// directory
 func PathsForSource(ctx PathContext, paths []string) Paths {
 	ret := make(Paths, len(paths))
 	for i, path := range paths {
@@ -289,9 +290,9 @@
 	return ret
 }
 
-// ExistentPathsForSources returns a list of Paths rooted from SrcDir that are
-// found in the tree. If any are not found, they are omitted from the list,
-// and dependencies are added so that we're re-run when they are added.
+// ExistentPathsForSources returns a list of Paths rooted from SrcDir, *not* rooted from the
+// module's local source directory, that are found in the tree. If any are not found, they are
+// omitted from the list, and dependencies are added so that we're re-run when they are added.
 func ExistentPathsForSources(ctx PathContext, paths []string) Paths {
 	ret := make(Paths, 0, len(paths))
 	for _, path := range paths {
@@ -395,6 +396,9 @@
 // `android:"path"` so that dependencies on other modules will have already been handled by the
 // path_properties mutator.
 func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList {
+	if paths == nil {
+		return bazel.LabelList{}
+	}
 	labels := bazel.LabelList{
 		Includes: []bazel.Label{},
 	}
@@ -1024,9 +1028,10 @@
 	return path
 }
 
-// ExistentPathForSource returns an OptionalPath with the SourcePath if the
-// path exists, or an empty OptionalPath if it doesn't exist. Dependencies are added
-// so that the ninja file will be regenerated if the state of the path changes.
+// ExistentPathForSource returns an OptionalPath with the SourcePath, rooted from SrcDir, *not*
+// rooted from the module's local source directory, if the path exists, or an empty OptionalPath if
+// it doesn't exist. Dependencies are added so that the ninja file will be regenerated if the state
+// of the path changes.
 func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPath {
 	path, err := pathForSource(ctx, pathComponents...)
 	if err != nil {
diff --git a/android/variable.go b/android/variable.go
index e76d683..76666c5 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -367,6 +367,10 @@
 	BoardMoveRecoveryResourcesToVendorBoot *bool `json:",omitempty"`
 
 	PrebuiltHiddenApiDir *string `json:",omitempty"`
+
+	ShippingApiLevel *string `json:",omitempty"`
+
+	BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/apex/apex.go b/apex/apex.go
index cfeac72..e06a967 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -208,6 +208,9 @@
 
 	// List of native tests that are embedded inside this APEX.
 	Tests []string
+
+	// List of filesystem images that are embedded inside this APEX bundle.
+	Filesystems []string
 }
 
 type apexMultilibProperties struct {
@@ -580,6 +583,7 @@
 	ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...)
 	ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...)
 	ctx.AddFarVariationDependencies(rustLibVariations, sharedLibTag, nativeModules.Rust_dyn_libs...)
+	ctx.AddFarVariationDependencies(target.Variations(), fsTag, nativeModules.Filesystems...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 5321d2a..ddde1b7 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -24,6 +24,7 @@
         "bzl_conversion_test.go",
         "cc_conversion_test.go",
         "conversion_test.go",
+        "sh_conversion_test.go",
         "testing.go",
     ],
     pluginFor: [
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index df554a0..422422b 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -17,7 +17,6 @@
 import (
 	"android/soong/android"
 	"android/soong/genrule"
-	"android/soong/sh"
 	"strings"
 	"testing"
 )
@@ -358,12 +357,6 @@
 					ruleClass: "genrule",
 					// Note: no bzlLoadLocation for native rules
 				},
-				BazelTarget{
-					name:      "sh_binary_target",
-					ruleClass: "sh_binary",
-					// Note: no bzlLoadLocation for native rules
-					// TODO(ruperts): Could open source the existing, experimental Starlark sh_ rules?
-				},
 			},
 			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary")
 load("//build/bazel/rules:java.bzl", "java_binary")`,
@@ -476,6 +469,21 @@
 		dir                                string
 	}{
 		{
+			description:                        "filegroup with does not specify srcs",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "fg_foo",
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				`filegroup(
+    name = "fg_foo",
+)`,
+			},
+		},
+		{
 			description:                        "filegroup with no srcs",
 			moduleTypeUnderTest:                "filegroup",
 			moduleTypeUnderTestFactory:         android.FileGroupFactory,
@@ -860,23 +868,6 @@
 )`,
 			},
 		},
-		{
-			description:                        "sh_binary test",
-			moduleTypeUnderTest:                "sh_binary",
-			moduleTypeUnderTestFactory:         sh.ShBinaryFactory,
-			moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build,
-			bp: `sh_binary {
-    name: "foo",
-    src: "foo.sh",
-    bazel_module: { bp2build_available: true },
-}`,
-			expectedBazelTargets: []string{`sh_binary(
-    name = "foo",
-    srcs = [
-        "foo.sh",
-    ],
-)`},
-		},
 	}
 
 	dir := "."
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
new file mode 100644
index 0000000..dcc75bd
--- /dev/null
+++ b/bp2build/sh_conversion_test.go
@@ -0,0 +1,134 @@
+// Copyright 2021 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.
+
+package bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/sh"
+	"strings"
+	"testing"
+)
+
+func TestShBinaryLoadStatement(t *testing.T) {
+	testCases := []struct {
+		bazelTargets           BazelTargets
+		expectedLoadStatements string
+	}{
+		{
+			bazelTargets: BazelTargets{
+				BazelTarget{
+					name:      "sh_binary_target",
+					ruleClass: "sh_binary",
+					// Note: no bzlLoadLocation for native rules
+					// TODO(ruperts): Could open source the existing, experimental Starlark sh_ rules?
+				},
+			},
+			expectedLoadStatements: ``,
+		},
+	}
+
+	for _, testCase := range testCases {
+		actual := testCase.bazelTargets.LoadStatements()
+		expected := testCase.expectedLoadStatements
+		if actual != expected {
+			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
+		}
+	}
+
+}
+
+func TestShBinaryBp2Build(t *testing.T) {
+	testCases := []struct {
+		description                        string
+		moduleTypeUnderTest                string
+		moduleTypeUnderTestFactory         android.ModuleFactory
+		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+		preArchMutators                    []android.RegisterMutatorFunc
+		depsMutators                       []android.RegisterMutatorFunc
+		bp                                 string
+		expectedBazelTargets               []string
+		filesystem                         map[string]string
+		dir                                string
+	}{
+		{
+			description:                        "sh_binary test",
+			moduleTypeUnderTest:                "sh_binary",
+			moduleTypeUnderTestFactory:         sh.ShBinaryFactory,
+			moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build,
+			bp: `sh_binary {
+    name: "foo",
+    src: "foo.sh",
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`sh_binary(
+    name = "foo",
+    srcs = [
+        "foo.sh",
+    ],
+)`},
+		},
+	}
+
+	dir := "."
+	for _, testCase := range testCases {
+		filesystem := make(map[string][]byte)
+		toParse := []string{
+			"Android.bp",
+		}
+		for f, content := range testCase.filesystem {
+			if strings.HasSuffix(f, "Android.bp") {
+				toParse = append(toParse, f)
+			}
+			filesystem[f] = []byte(content)
+		}
+		config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
+		ctx := android.NewTestContext(config)
+		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		for _, m := range testCase.depsMutators {
+			ctx.DepsBp2BuildMutators(m)
+		}
+		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+		ctx.RegisterForBazelConversion()
+
+		_, errs := ctx.ParseFileList(dir, toParse)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+		_, errs = ctx.ResolveDependencies(config)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+
+		checkDir := dir
+		if testCase.dir != "" {
+			checkDir = testCase.dir
+		}
+		bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[checkDir]
+		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+			t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
+		} else {
+			for i, target := range bazelTargets {
+				if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+					t.Errorf(
+						"%s: Expected generated Bazel target to be '%s', got '%s'",
+						testCase.description,
+						w,
+						g,
+					)
+				}
+			}
+		}
+	}
+}
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 71c7626..76186be 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -150,6 +150,8 @@
 		"-Wunguarded-availability",
 		// This macro allows the bionic versioning.h to indirectly determine whether the
 		// option -Wunguarded-availability is on or not.
+		"-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__",
+		// TODO: remove this once prebuilt SDKs are only using the above macro instead.
 		"-D__ANDROID_UNGUARDED_AVAILABILITY__",
 	}, " "))
 
diff --git a/cc/config/global.go b/cc/config/global.go
index ee41125..e60bb3d 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -144,8 +144,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r407598b"
-	ClangDefaultShortVersion = "12.0.2"
+	ClangDefaultVersion      = "clang-r412851"
+	ClangDefaultShortVersion = "12.0.3"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 850c8f9..57563eb 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -28,6 +28,8 @@
 // various `prebuilt_*` mutators.
 
 import (
+	"fmt"
+
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -208,6 +210,17 @@
 	return p.outputFilePath
 }
 
+var _ android.OutputFileProducer = (*PrebuiltEtc)(nil)
+
+func (p *PrebuiltEtc) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return android.Paths{p.outputFilePath}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
 func (p *PrebuiltEtc) SubDir() string {
 	if subDir := proptools.String(p.properties.Sub_dir); subDir != "" {
 		return subDir
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 4bc1823..c90929a 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -38,6 +38,9 @@
 }
 
 type bootimgProperties struct {
+	// Set the name of the output. Defaults to <module_name>.img.
+	Stem *string
+
 	// Path to the linux kernel prebuilt file
 	Kernel_prebuilt *string `android:"arch_variant,path"`
 
@@ -96,7 +99,7 @@
 }
 
 func (b *bootimg) installFileName() string {
-	return b.BaseModuleName() + ".img"
+	return proptools.StringDefault(b.properties.Stem, b.BaseModuleName()+".img")
 }
 
 func (b *bootimg) partitionName() string {
@@ -110,6 +113,7 @@
 	} else {
 		// TODO(jiyong): fix this
 		ctx.PropertyErrorf("vendor_boot", "only vendor_boot:true is supported")
+		return
 	}
 
 	if proptools.Bool(b.properties.Use_avb) {
@@ -123,7 +127,8 @@
 }
 
 func (b *bootimg) buildVendorBootImage(ctx android.ModuleContext) android.OutputPath {
-	output := android.PathForModuleOut(ctx, "unsigned.img").OutputPath
+	output := android.PathForModuleOut(ctx, "unsigned", b.installFileName()).OutputPath
+
 	builder := android.NewRuleBuilder(pctx, ctx)
 	cmd := builder.Command().BuiltTool("mkbootimg")
 
@@ -182,21 +187,20 @@
 }
 
 func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.OutputPath) android.OutputPath {
-	signedImage := android.PathForModuleOut(ctx, "signed.img").OutputPath
+	output := android.PathForModuleOut(ctx, b.installFileName()).OutputPath
 	key := android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key))
 
 	builder := android.NewRuleBuilder(pctx, ctx)
-	builder.Command().Text("cp").Input(unsignedImage).Output(signedImage)
+	builder.Command().Text("cp").Input(unsignedImage).Output(output)
 	builder.Command().
 		BuiltTool("avbtool").
 		Flag("add_hash_footer").
 		FlagWithArg("--partition_name ", b.partitionName()).
 		FlagWithInput("--key ", key).
-		FlagWithOutput("--image ", signedImage)
+		FlagWithOutput("--image ", output)
 
 	builder.Build("sign_bootimg", fmt.Sprintf("Signing %s", b.BaseModuleName()))
-
-	return signedImage
+	return output
 }
 
 var _ android.AndroidMkEntriesProvider = (*bootimg)(nil)
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 1651c1c..f8e41c4 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -221,13 +221,19 @@
 		return
 	}
 
+	classesJars := android.Paths{classesJar}
+	ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) {
+		javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+		classesJars = append(classesJars, javaInfo.ImplementationJars...)
+	})
+
 	stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags
 
 	flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        hiddenAPIGenerateCSVRule,
 		Description: "hiddenapi flags",
-		Input:       classesJar,
+		Inputs:      classesJars,
 		Output:      flagsCSV,
 		Implicit:    stubFlagsCSV,
 		Args: map[string]string{
@@ -241,7 +247,7 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        hiddenAPIGenerateCSVRule,
 		Description: "hiddenapi metadata",
-		Input:       classesJar,
+		Inputs:      classesJars,
 		Output:      metadataCSV,
 		Implicit:    stubFlagsCSV,
 		Args: map[string]string{
@@ -255,8 +261,9 @@
 	rule := android.NewRuleBuilder(pctx, ctx)
 	rule.Command().
 		BuiltTool("merge_csv").
-		FlagWithInput("--zip_input=", classesJar).
-		FlagWithOutput("--output=", indexCSV)
+		Flag("--zip_input").
+		FlagWithOutput("--output=", indexCSV).
+		Inputs(classesJars)
 	rule.Build("merged-hiddenapi-index", "Merged Hidden API index")
 	h.indexCSVPath = indexCSV
 
@@ -335,3 +342,16 @@
 		TransformZipAlign(ctx, output, tmpOutput)
 	}
 }
+
+type hiddenApiAnnotationsDependencyTag struct {
+	blueprint.BaseDependencyTag
+}
+
+// Tag used to mark dependencies on java_library instances that contains Java source files whose
+// sole purpose is to provide additional hiddenapi annotations.
+var hiddenApiAnnotationsTag hiddenApiAnnotationsDependencyTag
+
+// Mark this tag so dependencies that use it are excluded from APEX contents.
+func (t hiddenApiAnnotationsDependencyTag) ExcludeFromApexContents() {}
+
+var _ android.ExcludeFromApexContentsTag = hiddenApiAnnotationsTag
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index df825bb..4670d03 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -82,6 +82,10 @@
 			name: "foo",
 			srcs: ["a.java"],
 			compile_dex: true,
+
+			hiddenapi_additional_annotations: [
+				"foo-hiddenapi-annotations",
+			],
 		}
 
 		java_library {
@@ -90,6 +94,12 @@
 			compile_dex: true,
 		}
 
+		java_library {
+			name: "foo-hiddenapi-annotations",
+			srcs: ["a.java"],
+			compile_dex: true,
+		}
+
 		java_import {
 			name: "foo",
 			jars: ["a.jar"],
@@ -112,6 +122,15 @@
 .intermediates/foo/android_common/hiddenapi/index.csv
 `,
 		indexRule)
+
+	// Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that
+	// creates the index.csv file.
+	foo := ctx.ModuleForTests("foo", "android_common")
+	indexParams := foo.Output("hiddenapi/index.csv")
+	CheckHiddenAPIRuleInputs(t, `
+.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar
+.intermediates/foo/android_common/javac/foo.jar
+`, indexParams)
 }
 
 func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
diff --git a/java/java.go b/java/java.go
index 338140b..69ec2a4 100644
--- a/java/java.go
+++ b/java/java.go
@@ -298,6 +298,9 @@
 
 	// If true, package the kotlin stdlib into the jar.  Defaults to true.
 	Static_kotlin_stdlib *bool `android:"arch_variant"`
+
+	// A list of java_library instances that provide additional hiddenapi annotations for the library.
+	Hiddenapi_additional_annotations []string
 }
 
 type CompilerDeviceProperties struct {
@@ -840,6 +843,9 @@
 	libDeps := ctx.AddVariationDependencies(nil, libTag, rewriteSyspropLibs(j.properties.Libs, "libs")...)
 	ctx.AddVariationDependencies(nil, staticLibTag, rewriteSyspropLibs(j.properties.Static_libs, "static_libs")...)
 
+	// Add dependency on libraries that provide additional hidden api annotations.
+	ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...)
+
 	if ctx.DeviceConfig().VndkVersion() != "" && ctx.Config().EnforceInterPartitionJavaSdkLibrary() {
 		// Require java_sdk_library at inter-partition java dependency to ensure stable
 		// interface between partitions. If inter-partition java_library dependency is detected,
@@ -2426,7 +2432,7 @@
 
 	// list of files or filegroup modules that provide data that should be installed alongside
 	// the test
-	Data []string `android:"path,arch_variant"`
+	Data []string `android:"path"`
 
 	// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
 	// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
diff --git a/java/sdk.go b/java/sdk.go
index 7290711..74d5a81 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -641,14 +641,26 @@
 
 	if ctx.Config().PlatformSdkCodename() == "REL" {
 		cmd.Text("echo REL >").Output(out)
-	} else if !ctx.Config().AlwaysUsePrebuiltSdks() {
-		in, err := ctx.GlobWithDeps("frameworks/base/api/*current.txt", nil)
-		if err != nil {
-			ctx.Errorf("error globbing API files: %s", err)
+	} else if ctx.Config().FrameworksBaseDirExists(ctx) && !ctx.Config().AlwaysUsePrebuiltSdks() {
+		cmd.Text("cat")
+		apiTxtFileModules := []string{
+			"frameworks-base-api-current.txt",
+			"frameworks-base-api-system-current.txt",
+			"frameworks-base-api-module-lib-current.txt",
 		}
-
-		cmd.Text("cat").
-			Inputs(android.PathsForSource(ctx, in)).
+		count := 0
+		ctx.VisitAllModules(func(module android.Module) {
+			name := ctx.ModuleName(module)
+			if android.InList(name, apiTxtFileModules) {
+				cmd.Inputs(android.OutputFilesForModule(ctx, module, ""))
+				count++
+			}
+		})
+		if count != len(apiTxtFileModules) {
+			ctx.Errorf("Could not find all the expected API modules %v, found %d\n", apiTxtFileModules, count)
+			return
+		}
+		cmd.Input(android.PathForSource(ctx, "frameworks/base/services/api/current.txt")).
 			Text("| md5sum | cut -d' ' -f1 >").
 			Output(out)
 	} else {
diff --git a/scripts/hiddenapi/merge_csv.py b/scripts/hiddenapi/merge_csv.py
index 6a5b0e1..5ad61b2 100755
--- a/scripts/hiddenapi/merge_csv.py
+++ b/scripts/hiddenapi/merge_csv.py
@@ -26,7 +26,8 @@
 args_parser = argparse.ArgumentParser(description='Merge given CSV files into a single one.')
 args_parser.add_argument('--header', help='Comma separated field names; '
                                           'if missing determines the header from input files.')
-args_parser.add_argument('--zip_input', help='ZIP archive with all CSV files to merge.')
+args_parser.add_argument('--zip_input', help='Treat files as ZIP archives containing CSV files to merge.',
+                         action="store_true")
 args_parser.add_argument('--output', help='Output file for merged CSV.',
                          default='-', type=argparse.FileType('w'))
 args_parser.add_argument('files', nargs=argparse.REMAINDER)
@@ -36,20 +37,16 @@
 def dict_reader(input):
     return csv.DictReader(input, delimiter=',', quotechar='|')
 
-
-if args.zip_input and len(args.files) > 0:
-    raise ValueError('Expecting either a single ZIP with CSV files'
-                     ' or a list of CSV files as input; not both.')
-
 csv_readers = []
-if len(args.files) > 0:
+if not(args.zip_input):
     for file in args.files:
         csv_readers.append(dict_reader(open(file, 'r')))
-elif args.zip_input:
-    with ZipFile(args.zip_input) as zip:
-        for entry in zip.namelist():
-            if entry.endswith('.uau'):
-                csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
+else:
+    for file in args.files:
+        with ZipFile(file) as zip:
+            for entry in zip.namelist():
+                if entry.endswith('.uau'):
+                    csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
 
 headers = set()
 if args.header: