Merge "Script to set up android build directory"
diff --git a/android/config.go b/android/config.go
index 3dae6e2..da4f8e2 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1029,7 +1029,7 @@
 }
 
 func (c *deviceConfig) NativeCoverageEnabled() bool {
-	return Bool(c.config.productVariables.NativeCoverage)
+	return Bool(c.config.productVariables.Native_coverage)
 }
 
 func (c *deviceConfig) ClangCoverageEnabled() bool {
diff --git a/android/sdk.go b/android/sdk.go
index 006b3a0..27756ce 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -218,6 +218,25 @@
 	Variants() []SdkAware
 }
 
+type SdkMemberTypeDependencyTag interface {
+	blueprint.DependencyTag
+
+	SdkMemberType() SdkMemberType
+}
+
+type sdkMemberDependencyTag struct {
+	blueprint.BaseDependencyTag
+	memberType SdkMemberType
+}
+
+func (t *sdkMemberDependencyTag) SdkMemberType() SdkMemberType {
+	return t.memberType
+}
+
+func DependencyTagForSdkMemberType(memberType SdkMemberType) SdkMemberTypeDependencyTag {
+	return &sdkMemberDependencyTag{memberType: memberType}
+}
+
 // Interface that must be implemented for every type that can be a member of an
 // sdk.
 //
diff --git a/android/variable.go b/android/variable.go
index 51306ad..c277acc 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -125,6 +125,11 @@
 		Experimental_mte struct {
 			Cflags []string `android:"arch_variant"`
 		} `android:"arch_variant"`
+
+		Native_coverage struct {
+			Srcs         []string `android:"arch_variant"`
+			Exclude_srcs []string `android:"arch_variant"`
+		} `android:"arch_variant"`
 	} `android:"arch_variant"`
 }
 
@@ -247,7 +252,7 @@
 	ClangTidy  *bool   `json:",omitempty"`
 	TidyChecks *string `json:",omitempty"`
 
-	NativeCoverage       *bool    `json:",omitempty"`
+	Native_coverage      *bool    `json:",omitempty"`
 	ClangCoverage        *bool    `json:",omitempty"`
 	CoveragePaths        []string `json:",omitempty"`
 	CoverageExcludePaths []string `json:",omitempty"`
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 391072e..dd08f03 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -82,7 +82,7 @@
 				notice: "custom_notice",
 			}
 		`, func(fs map[string][]byte, config android.Config) {
-			config.TestProductVariables.NativeCoverage = proptools.BoolPtr(true)
+			config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
 		})
 
 		files := getFiles(t, ctx, "myapex", "android_common_image")
diff --git a/cc/ccdeps.go b/cc/ccdeps.go
index 4e23a7b..225405c 100644
--- a/cc/ccdeps.go
+++ b/cc/ccdeps.go
@@ -17,7 +17,6 @@
 import (
 	"encoding/json"
 	"fmt"
-	"os"
 	"path"
 	"sort"
 	"strings"
@@ -106,7 +105,7 @@
 
 	moduleDeps.Modules = moduleInfos
 
-	ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName).String()
+	ccfpath := android.PathForOutput(ctx, ccdepsJsonFileName)
 	err := createJsonFile(moduleDeps, ccfpath)
 	if err != nil {
 		ctx.Errorf(err.Error())
@@ -236,17 +235,14 @@
 	return m
 }
 
-func createJsonFile(moduleDeps ccDeps, ccfpath string) error {
-	file, err := os.Create(ccfpath)
-	if err != nil {
-		return fmt.Errorf("Failed to create file: %s, relative: %v", ccdepsJsonFileName, err)
-	}
-	defer file.Close()
-	moduleDeps.Modules = sortMap(moduleDeps.Modules)
+func createJsonFile(moduleDeps ccDeps, ccfpath android.WritablePath) error {
 	buf, err := json.MarshalIndent(moduleDeps, "", "\t")
 	if err != nil {
-		return fmt.Errorf("Write file failed: %s, relative: %v", ccdepsJsonFileName, err)
+		return fmt.Errorf("JSON marshal of cc deps failed: %s", err)
 	}
-	fmt.Fprintf(file, string(buf))
+	err = android.WriteFileToOutputDir(ccfpath, buf, 0666)
+	if err != nil {
+		return fmt.Errorf("Writing cc deps to %s failed: %s", ccfpath.String(), err)
+	}
 	return nil
 }
diff --git a/cc/config/global.go b/cc/config/global.go
index 44de4d5..ec09d22 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -168,6 +168,9 @@
 			flags = append(flags, "-ftrivial-auto-var-init=pattern")
 		} else if ctx.Config().IsEnvTrue("AUTO_UNINITIALIZE") {
 			flags = append(flags, "-ftrivial-auto-var-init=uninitialized")
+		} else {
+			// Default to pattern initialization.
+			flags = append(flags, "-ftrivial-auto-var-init=pattern")
 		}
 
 		return strings.Join(flags, " ")
diff --git a/cc/pgo.go b/cc/pgo.go
index e341d03..8eb3400 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -41,9 +41,9 @@
 var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects")
 
 const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
-const profileSamplingFlag = "-gline-tables-only"
+const profileSamplingFlag = "-gmlt -fdebug-info-for-profiling"
 const profileUseInstrumentFormat = "-fprofile-use=%s"
-const profileUseSamplingFormat = "-fprofile-sample-use=%s"
+const profileUseSamplingFormat = "-fprofile-sample-accurate -fprofile-sample-use=%s"
 
 func getPgoProfileProjects(config android.DeviceConfig) []string {
 	return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string {
diff --git a/java/java_test.go b/java/java_test.go
index a2788cb..c4ab13d 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1043,6 +1043,12 @@
 		    libs: ["baz"],
 		    sdk_version: "system_current",
 		}
+		java_library {
+			name: "baz-test",
+			srcs: ["c.java"],
+			libs: ["foo"],
+			sdk_version: "test_current",
+		}
 		`)
 
 	// check the existence of the internal modules
@@ -1075,6 +1081,13 @@
 			"foo.stubs.jar")
 	}
 
+	bazTestJavac := ctx.ModuleForTests("baz-test", "android_common").Rule("javac")
+	// tests if baz-test is actually linked to the test stubs lib
+	if !strings.Contains(bazTestJavac.Args["classpath"], "foo.stubs.test.jar") {
+		t.Errorf("baz-test javac classpath %v does not contain %q", bazTestJavac.Args["classpath"],
+			"foo.stubs.test.jar")
+	}
+
 	// test if baz has exported SDK lib names foo and bar to qux
 	qux := ctx.ModuleForTests("qux", "android_common")
 	if quxLib, ok := qux.Module().(*Library); ok {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 530e02c..d51d317 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+
 	"fmt"
 	"io"
 	"path"
@@ -24,6 +25,7 @@
 	"strings"
 	"sync"
 
+	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -53,21 +55,96 @@
 		`</permissions>\n`
 )
 
+// A tag to associated a dependency with a specific api scope.
+type scopeDependencyTag struct {
+	blueprint.BaseDependencyTag
+	name     string
+	apiScope *apiScope
+}
+
+// Provides information about an api scope, e.g. public, system, test.
+type apiScope struct {
+	// The name of the api scope, e.g. public, system, test
+	name string
+
+	// The tag to use to depend on the stubs library module.
+	stubsTag scopeDependencyTag
+
+	// The tag to use to depend on the stubs
+	apiFileTag scopeDependencyTag
+
+	// The scope specific prefix to add to the api file base of "current.txt" or "removed.txt".
+	apiFilePrefix string
+
+	// The scope specific prefix to add to the sdk library module name to construct a scope specific
+	// module name.
+	moduleSuffix string
+
+	// The suffix to add to the make variable that references the location of the api file.
+	apiFileMakeVariableSuffix string
+
+	// SDK version that the stubs library is built against. Note that this is always
+	// *current. Older stubs library built with a numbered SDK version is created from
+	// the prebuilt jar.
+	sdkVersion string
+}
+
+// Initialize a scope, creating and adding appropriate dependency tags
+func initApiScope(scope *apiScope) *apiScope {
+	//apiScope := &scope
+	scope.stubsTag = scopeDependencyTag{
+		name:     scope.name + "-stubs",
+		apiScope: scope,
+	}
+	scope.apiFileTag = scopeDependencyTag{
+		name:     scope.name + "-api",
+		apiScope: scope,
+	}
+	return scope
+}
+
+func (scope *apiScope) stubsModuleName(baseName string) string {
+	return baseName + sdkStubsLibrarySuffix + scope.moduleSuffix
+}
+
+func (scope *apiScope) docsModuleName(baseName string) string {
+	return baseName + sdkDocsSuffix + scope.moduleSuffix
+}
+
+type apiScopes []*apiScope
+
+func (scopes apiScopes) Strings(accessor func(*apiScope) string) []string {
+	var list []string
+	for _, scope := range scopes {
+		list = append(list, accessor(scope))
+	}
+	return list
+}
+
 var (
-	publicApiStubsTag = dependencyTag{name: "public"}
-	systemApiStubsTag = dependencyTag{name: "system"}
-	testApiStubsTag   = dependencyTag{name: "test"}
-	publicApiFileTag  = dependencyTag{name: "publicApi"}
-	systemApiFileTag  = dependencyTag{name: "systemApi"}
-	testApiFileTag    = dependencyTag{name: "testApi"}
-)
-
-type apiScope int
-
-const (
-	apiScopePublic apiScope = iota
-	apiScopeSystem
-	apiScopeTest
+	apiScopePublic = initApiScope(&apiScope{
+		name:       "public",
+		sdkVersion: "current",
+	})
+	apiScopeSystem = initApiScope(&apiScope{
+		name:                      "system",
+		apiFilePrefix:             "system-",
+		moduleSuffix:              sdkSystemApiSuffix,
+		apiFileMakeVariableSuffix: "_SYSTEM",
+		sdkVersion:                "system_current",
+	})
+	apiScopeTest = initApiScope(&apiScope{
+		name:                      "test",
+		apiFilePrefix:             "test-",
+		moduleSuffix:              sdkTestApiSuffix,
+		apiFileMakeVariableSuffix: "_TEST",
+		sdkVersion:                "test_current",
+	})
+	allApiScopes = apiScopes{
+		apiScopePublic,
+		apiScopeSystem,
+		apiScopeTest,
+	}
 )
 
 var (
@@ -142,22 +219,18 @@
 	//Html_doc *bool
 }
 
+type scopePaths struct {
+	stubsHeaderPath android.Paths
+	stubsImplPath   android.Paths
+	apiFilePath     android.Path
+}
+
 type SdkLibrary struct {
 	Library
 
 	sdkLibraryProperties sdkLibraryProperties
 
-	publicApiStubsPath android.Paths
-	systemApiStubsPath android.Paths
-	testApiStubsPath   android.Paths
-
-	publicApiStubsImplPath android.Paths
-	systemApiStubsImplPath android.Paths
-	testApiStubsImplPath   android.Paths
-
-	publicApiFilePath android.Path
-	systemApiFilePath android.Path
-	testApiFilePath   android.Path
+	scopePaths map[*apiScope]*scopePaths
 
 	permissionsFile android.Path
 }
@@ -165,21 +238,36 @@
 var _ Dependency = (*SdkLibrary)(nil)
 var _ SdkLibraryDependency = (*SdkLibrary)(nil)
 
+func (module *SdkLibrary) getActiveApiScopes() apiScopes {
+	if module.sdkLibraryProperties.Has_system_and_test_apis {
+		return allApiScopes
+	} else {
+		return apiScopes{apiScopePublic}
+	}
+}
+
+func (module *SdkLibrary) getScopePaths(scope *apiScope) *scopePaths {
+	if module.scopePaths == nil {
+		module.scopePaths = make(map[*apiScope]*scopePaths)
+	}
+	paths := module.scopePaths[scope]
+	if paths == nil {
+		paths = &scopePaths{}
+		module.scopePaths[scope] = paths
+	}
+
+	return paths
+}
+
 func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	useBuiltStubs := !ctx.Config().UnbundledBuildUsePrebuiltSdks()
-	// Add dependencies to the stubs library
-	if useBuiltStubs {
-		ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic))
-	}
-	ctx.AddVariationDependencies(nil, publicApiFileTag, module.docsName(apiScopePublic))
-
-	if module.sdkLibraryProperties.Has_system_and_test_apis {
+	for _, apiScope := range module.getActiveApiScopes() {
+		// Add dependencies to the stubs library
 		if useBuiltStubs {
-			ctx.AddVariationDependencies(nil, systemApiStubsTag, module.stubsName(apiScopeSystem))
-			ctx.AddVariationDependencies(nil, testApiStubsTag, module.stubsName(apiScopeTest))
+			ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsName(apiScope))
 		}
-		ctx.AddVariationDependencies(nil, systemApiFileTag, module.docsName(apiScopeSystem))
-		ctx.AddVariationDependencies(nil, testApiFileTag, module.docsName(apiScopeTest))
+
+		ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.docsName(apiScope))
 	}
 
 	module.Library.deps(ctx)
@@ -194,34 +282,26 @@
 	module.buildPermissionsFile(ctx)
 
 	// Record the paths to the header jars of the library (stubs and impl).
-	// When this java_sdk_library is dependened from others via "libs" property,
+	// When this java_sdk_library is depended upon from others via "libs" property,
 	// the recorded paths will be returned depending on the link type of the caller.
 	ctx.VisitDirectDeps(func(to android.Module) {
 		otherName := ctx.OtherModuleName(to)
 		tag := ctx.OtherModuleDependencyTag(to)
 
 		if lib, ok := to.(Dependency); ok {
-			switch tag {
-			case publicApiStubsTag:
-				module.publicApiStubsPath = lib.HeaderJars()
-				module.publicApiStubsImplPath = lib.ImplementationJars()
-			case systemApiStubsTag:
-				module.systemApiStubsPath = lib.HeaderJars()
-				module.systemApiStubsImplPath = lib.ImplementationJars()
-			case testApiStubsTag:
-				module.testApiStubsPath = lib.HeaderJars()
-				module.testApiStubsImplPath = lib.ImplementationJars()
+			if scopeTag, ok := tag.(scopeDependencyTag); ok {
+				apiScope := scopeTag.apiScope
+				scopePaths := module.getScopePaths(apiScope)
+				scopePaths.stubsHeaderPath = lib.HeaderJars()
+				scopePaths.stubsImplPath = lib.ImplementationJars()
 			}
 		}
 		if doc, ok := to.(ApiFilePath); ok {
-			switch tag {
-			case publicApiFileTag:
-				module.publicApiFilePath = doc.ApiFilePath()
-			case systemApiFileTag:
-				module.systemApiFilePath = doc.ApiFilePath()
-			case testApiFileTag:
-				module.testApiFilePath = doc.ApiFilePath()
-			default:
+			if scopeTag, ok := tag.(scopeDependencyTag); ok {
+				apiScope := scopeTag.apiScope
+				scopePaths := module.getScopePaths(apiScope)
+				scopePaths.apiFilePath = doc.ApiFilePath()
+			} else {
 				ctx.ModuleErrorf("depends on module %q of unknown tag %q", otherName, tag)
 			}
 		}
@@ -273,42 +353,23 @@
 						owner = "android"
 					}
 				}
-				// Create dist rules to install the stubs libs to the dist dir
-				if len(module.publicApiStubsPath) == 1 {
-					fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-						module.publicApiStubsImplPath.Strings()[0]+
-						":"+path.Join("apistubs", owner, "public",
-						module.BaseModuleName()+".jar")+")")
-				}
-				if len(module.systemApiStubsPath) == 1 {
-					fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-						module.systemApiStubsImplPath.Strings()[0]+
-						":"+path.Join("apistubs", owner, "system",
-						module.BaseModuleName()+".jar")+")")
-				}
-				if len(module.testApiStubsPath) == 1 {
-					fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-						module.testApiStubsImplPath.Strings()[0]+
-						":"+path.Join("apistubs", owner, "test",
-						module.BaseModuleName()+".jar")+")")
-				}
-				if module.publicApiFilePath != nil {
-					fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-						module.publicApiFilePath.String()+
-						":"+path.Join("apistubs", owner, "public", "api",
-						module.BaseModuleName()+".txt")+")")
-				}
-				if module.systemApiFilePath != nil {
-					fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-						module.systemApiFilePath.String()+
-						":"+path.Join("apistubs", owner, "system", "api",
-						module.BaseModuleName()+".txt")+")")
-				}
-				if module.testApiFilePath != nil {
-					fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
-						module.testApiFilePath.String()+
-						":"+path.Join("apistubs", owner, "test", "api",
-						module.BaseModuleName()+".txt")+")")
+
+				// Create dist rules to install the stubs libs and api files to the dist dir
+				for _, apiScope := range module.getActiveApiScopes() {
+					if scopePaths, ok := module.scopePaths[apiScope]; ok {
+						if len(scopePaths.stubsHeaderPath) == 1 {
+							fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+								scopePaths.stubsImplPath.Strings()[0]+
+								":"+path.Join("apistubs", owner, apiScope.name,
+								module.BaseModuleName()+".jar")+")")
+						}
+						if scopePaths.apiFilePath != nil {
+							fmt.Fprintln(w, "$(call dist-for-goals,sdk win_sdk,"+
+								scopePaths.apiFilePath.String()+
+								":"+path.Join("apistubs", owner, apiScope.name, "api",
+								module.BaseModuleName()+".txt")+")")
+						}
+					}
 				}
 			}
 		},
@@ -317,27 +378,13 @@
 }
 
 // Module name of the stubs library
-func (module *SdkLibrary) stubsName(apiScope apiScope) string {
-	stubsName := module.BaseModuleName() + sdkStubsLibrarySuffix
-	switch apiScope {
-	case apiScopeSystem:
-		stubsName = stubsName + sdkSystemApiSuffix
-	case apiScopeTest:
-		stubsName = stubsName + sdkTestApiSuffix
-	}
-	return stubsName
+func (module *SdkLibrary) stubsName(apiScope *apiScope) string {
+	return apiScope.stubsModuleName(module.BaseModuleName())
 }
 
 // Module name of the docs
-func (module *SdkLibrary) docsName(apiScope apiScope) string {
-	docsName := module.BaseModuleName() + sdkDocsSuffix
-	switch apiScope {
-	case apiScopeSystem:
-		docsName = docsName + sdkSystemApiSuffix
-	case apiScopeTest:
-		docsName = docsName + sdkTestApiSuffix
-	}
-	return docsName
+func (module *SdkLibrary) docsName(apiScope *apiScope) string {
+	return apiScope.docsModuleName(module.BaseModuleName())
 }
 
 // Module name of the runtime implementation library
@@ -371,28 +418,12 @@
 	return module.BaseModuleName() + sdkXmlFileSuffix
 }
 
-// SDK version that the stubs library is built against. Note that this is always
-// *current. Older stubs library built with a numberd SDK version is created from
-// the prebuilt jar.
-func (module *SdkLibrary) sdkVersionForScope(apiScope apiScope) string {
-	switch apiScope {
-	case apiScopePublic:
-		return "current"
-	case apiScopeSystem:
-		return "system_current"
-	case apiScopeTest:
-		return "test_current"
-	default:
-		return "current"
-	}
-}
-
 // Get the sdk version for use when compiling the stubs library.
-func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope apiScope) string {
+func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) string {
 	sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library))
 	if sdkDep.hasStandardLibs() {
 		// If building against a standard sdk then use the sdk version appropriate for the scope.
-		return module.sdkVersionForScope(apiScope)
+		return apiScope.sdkVersion
 	} else {
 		// Otherwise, use no system module.
 		return "none"
@@ -402,47 +433,20 @@
 // $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated
 // api file for the current source
 // TODO: remove this when apicheck is done in soong
-func (module *SdkLibrary) apiTagName(apiScope apiScope) string {
-	apiTagName := strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1)
-	switch apiScope {
-	case apiScopeSystem:
-		apiTagName = apiTagName + "_SYSTEM"
-	case apiScopeTest:
-		apiTagName = apiTagName + "_TEST"
-	}
-	return apiTagName
+func (module *SdkLibrary) apiTagName(apiScope *apiScope) string {
+	return strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1) + apiScope.apiFileMakeVariableSuffix
 }
 
-func (module *SdkLibrary) latestApiFilegroupName(apiScope apiScope) string {
-	name := ":" + module.BaseModuleName() + ".api."
-	switch apiScope {
-	case apiScopePublic:
-		name = name + "public"
-	case apiScopeSystem:
-		name = name + "system"
-	case apiScopeTest:
-		name = name + "test"
-	}
-	name = name + ".latest"
-	return name
+func (module *SdkLibrary) latestApiFilegroupName(apiScope *apiScope) string {
+	return ":" + module.BaseModuleName() + ".api." + apiScope.name + ".latest"
 }
 
-func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope apiScope) string {
-	name := ":" + module.BaseModuleName() + "-removed.api."
-	switch apiScope {
-	case apiScopePublic:
-		name = name + "public"
-	case apiScopeSystem:
-		name = name + "system"
-	case apiScopeTest:
-		name = name + "test"
-	}
-	name = name + ".latest"
-	return name
+func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope *apiScope) string {
+	return ":" + module.BaseModuleName() + "-removed.api." + apiScope.name + ".latest"
 }
 
 // Creates a static java library that has API stubs
-func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiScope apiScope) {
+func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiScope *apiScope) {
 	props := struct {
 		Name                *string
 		Srcs                []string
@@ -505,7 +509,7 @@
 
 // Creates a droiddoc module that creates stubs source files from the given full source
 // files
-func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope apiScope) {
+func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope *apiScope) {
 	props := struct {
 		Name                             *string
 		Srcs                             []string
@@ -590,16 +594,8 @@
 	// List of APIs identified from the provided source files are created. They are later
 	// compared against to the not-yet-released (a.k.a current) list of APIs and to the
 	// last-released (a.k.a numbered) list of API.
-	currentApiFileName := "current.txt"
-	removedApiFileName := "removed.txt"
-	switch apiScope {
-	case apiScopeSystem:
-		currentApiFileName = "system-" + currentApiFileName
-		removedApiFileName = "system-" + removedApiFileName
-	case apiScopeTest:
-		currentApiFileName = "test-" + currentApiFileName
-		removedApiFileName = "test-" + removedApiFileName
-	}
+	currentApiFileName := apiScope.apiFilePrefix + "current.txt"
+	removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
 	apiDir := module.getApiDir()
 	currentApiFileName = path.Join(apiDir, currentApiFileName)
 	removedApiFileName = path.Join(apiDir, removedApiFileName)
@@ -677,38 +673,51 @@
 	return android.Paths{jarPath.Path()}
 }
 
-// to satisfy SdkLibraryDependency interface
-func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+func (module *SdkLibrary) sdkJars(
+	ctx android.BaseModuleContext,
+	sdkVersion sdkSpec,
+	headerJars bool) android.Paths {
+
 	// This module is just a wrapper for the stubs.
 	if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
 		return module.PrebuiltJars(ctx, sdkVersion)
 	} else {
+		if !sdkVersion.specified() {
+			if headerJars {
+				return module.Library.HeaderJars()
+			} else {
+				return module.Library.ImplementationJars()
+			}
+		}
+		var apiScope *apiScope
 		switch sdkVersion.kind {
 		case sdkSystem:
-			return module.systemApiStubsPath
+			apiScope = apiScopeSystem
+		case sdkTest:
+			apiScope = apiScopeTest
 		case sdkPrivate:
 			return module.Library.HeaderJars()
 		default:
-			return module.publicApiStubsPath
+			apiScope = apiScopePublic
+		}
+
+		paths := module.getScopePaths(apiScope)
+		if headerJars {
+			return paths.stubsHeaderPath
+		} else {
+			return paths.stubsImplPath
 		}
 	}
 }
 
 // to satisfy SdkLibraryDependency interface
+func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+	return module.sdkJars(ctx, sdkVersion, true /*headerJars*/)
+}
+
+// to satisfy SdkLibraryDependency interface
 func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
-	// This module is just a wrapper for the stubs.
-	if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
-		return module.PrebuiltJars(ctx, sdkVersion)
-	} else {
-		switch sdkVersion.kind {
-		case sdkSystem:
-			return module.systemApiStubsImplPath
-		case sdkPrivate:
-			return module.Library.ImplementationJars()
-		default:
-			return module.publicApiStubsImplPath
-		}
-	}
+	return module.sdkJars(ctx, sdkVersion, false /*headerJars*/)
 }
 
 func (module *SdkLibrary) SetNoDist() {
@@ -744,17 +753,14 @@
 	module.sdkLibraryProperties.Has_system_and_test_apis = hasSystemAndTestApis
 	module.sdkLibraryProperties.No_dist = proptools.BoolPtr(!hasSystemAndTestApis)
 
-	scopes := []string{""}
-	if hasSystemAndTestApis {
-		scopes = append(scopes, "system-", "test-")
-	}
-
 	missing_current_api := false
 
+	activeScopes := module.getActiveApiScopes()
+
 	apiDir := module.getApiDir()
-	for _, scope := range scopes {
+	for _, scope := range activeScopes {
 		for _, api := range []string{"current.txt", "removed.txt"} {
-			path := path.Join(mctx.ModuleDir(), apiDir, scope+api)
+			path := path.Join(mctx.ModuleDir(), apiDir, scope.apiFilePrefix+api)
 			p := android.ExistentPathForSource(mctx, path)
 			if !p.Valid() {
 				mctx.ModuleErrorf("Current api file %#v doesn't exist", path)
@@ -774,22 +780,14 @@
 		mctx.ModuleErrorf("One or more current api files are missing. "+
 			"You can update them by:\n"+
 			"%s %q %s && m update-api",
-			script, filepath.Join(mctx.ModuleDir(), apiDir), strings.Join(scopes, " "))
+			script, filepath.Join(mctx.ModuleDir(), apiDir),
+			strings.Join(activeScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " "))
 		return
 	}
 
-	// for public API stubs
-	module.createStubsLibrary(mctx, apiScopePublic)
-	module.createStubsSources(mctx, apiScopePublic)
-
-	if hasSystemAndTestApis {
-		// for system API stubs
-		module.createStubsLibrary(mctx, apiScopeSystem)
-		module.createStubsSources(mctx, apiScopeSystem)
-
-		// for test API stubs
-		module.createStubsLibrary(mctx, apiScopeTest)
-		module.createStubsSources(mctx, apiScopeTest)
+	for _, scope := range activeScopes {
+		module.createStubsLibrary(mctx, scope)
+		module.createStubsSources(mctx, scope)
 	}
 
 	if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
@@ -909,7 +907,7 @@
 
 func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies to the prebuilt stubs library
-	ctx.AddVariationDependencies(nil, publicApiStubsTag, module.BaseModuleName()+sdkStubsLibrarySuffix)
+	ctx.AddVariationDependencies(nil, apiScopePublic.stubsTag, module.BaseModuleName()+sdkStubsLibrarySuffix)
 }
 
 func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -918,7 +916,7 @@
 		tag := ctx.OtherModuleDependencyTag(to)
 
 		switch tag {
-		case publicApiStubsTag:
+		case apiScopePublic.stubsTag:
 			module.stubsPath = to.(Dependency).HeaderJars()
 		}
 	})
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 3b0752f..f22763c 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -65,11 +65,6 @@
 	Module_exports bool `blueprint:"mutated"`
 }
 
-type sdkMemberDependencyTag struct {
-	blueprint.BaseDependencyTag
-	memberType android.SdkMemberType
-}
-
 // Contains information about the sdk properties that list sdk members, e.g.
 // Java_header_libs.
 type sdkMemberListProperty struct {
@@ -81,7 +76,7 @@
 
 	// the dependency tag used for items in this list that can be used to determine the memberType
 	// for a resolved dependency.
-	dependencyTag *sdkMemberDependencyTag
+	dependencyTag android.SdkMemberTypeDependencyTag
 }
 
 func (p *sdkMemberListProperty) propertyName() string {
@@ -167,9 +162,7 @@
 
 			memberType: memberType,
 
-			dependencyTag: &sdkMemberDependencyTag{
-				memberType: memberType,
-			},
+			dependencyTag: android.DependencyTagForSdkMemberType(memberType),
 		}
 
 		listProperties = append(listProperties, memberListProperty)
diff --git a/sdk/update.go b/sdk/update.go
index 0d2e4e4..97bafa1 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -113,8 +113,8 @@
 
 	ctx.VisitDirectDeps(func(m android.Module) {
 		tag := ctx.OtherModuleDependencyTag(m)
-		if memberTag, ok := tag.(*sdkMemberDependencyTag); ok {
-			memberType := memberTag.memberType
+		if memberTag, ok := tag.(android.SdkMemberTypeDependencyTag); ok {
+			memberType := memberTag.SdkMemberType()
 
 			// Make sure that the resolved module is allowed in the member list property.
 			if !memberType.IsInstance(m) {