Support NDK variant of cc_api_variant

Update cc build logic to support NDK variant of cc_api_variant. Any
cc_api_library with NDK variant of cc_api_variant would be treated as
similar with NDK library.

Bug: 259007436
Test: Cuttlefish vendor build succeeded
Change-Id: I75a7475f4fdcbac779f5aa64e76c60f94ea7ea1a
diff --git a/cc/cc.go b/cc/cc.go
index 8b3f456..2ff5bba 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2314,28 +2314,23 @@
 	return nonvariantLibs, variantLibs
 }
 
-func updateDepsWithApiImports(deps Deps, apiImports multitree.ApiImportInfo) Deps {
-	for idx, lib := range deps.SharedLibs {
-		deps.SharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
+func rewriteLibsForApiImports(c LinkableInterface, libs []string, replaceList map[string]string, config android.Config) ([]string, []string) {
+	nonVariantLibs := []string{}
+	variantLibs := []string{}
+
+	for _, lib := range libs {
+		replaceLibName := GetReplaceModuleName(lib, replaceList)
+		if replaceLibName == lib {
+			// Do not handle any libs which are not in API imports
+			nonVariantLibs = append(nonVariantLibs, replaceLibName)
+		} else if c.UseSdk() && inList(replaceLibName, *getNDKKnownLibs(config)) {
+			variantLibs = append(variantLibs, replaceLibName)
+		} else {
+			nonVariantLibs = append(nonVariantLibs, replaceLibName)
+		}
 	}
 
-	for idx, lib := range deps.LateSharedLibs {
-		deps.LateSharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
-	}
-
-	for idx, lib := range deps.RuntimeLibs {
-		deps.RuntimeLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
-	}
-
-	for idx, lib := range deps.SystemSharedLibs {
-		deps.SystemSharedLibs[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
-	}
-
-	for idx, lib := range deps.ReexportSharedLibHeaders {
-		deps.ReexportSharedLibHeaders[idx] = GetReplaceModuleName(lib, apiImports.SharedLibs)
-	}
-
-	return deps
+	return nonVariantLibs, variantLibs
 }
 
 func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
@@ -2354,8 +2349,15 @@
 	deps := c.deps(ctx)
 	apiImportInfo := GetApiImports(c, actx)
 
+	apiNdkLibs := []string{}
+	apiLateNdkLibs := []string{}
+
 	if ctx.Os() == android.Android && c.Target().NativeBridge != android.NativeBridgeEnabled {
-		deps = updateDepsWithApiImports(deps, apiImportInfo)
+		deps.SharedLibs, apiNdkLibs = rewriteLibsForApiImports(c, deps.SharedLibs, apiImportInfo.SharedLibs, ctx.Config())
+		deps.LateSharedLibs, apiLateNdkLibs = rewriteLibsForApiImports(c, deps.LateSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
+		deps.SystemSharedLibs, _ = rewriteLibsForApiImports(c, deps.SystemSharedLibs, apiImportInfo.SharedLibs, ctx.Config())
+		deps.ReexportHeaderLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportHeaderLibHeaders, apiImportInfo.SharedLibs, ctx.Config())
+		deps.ReexportSharedLibHeaders, _ = rewriteLibsForApiImports(c, deps.ReexportSharedLibHeaders, apiImportInfo.SharedLibs, ctx.Config())
 	}
 
 	c.Properties.AndroidMkSystemSharedLibs = deps.SystemSharedLibs
@@ -2542,12 +2544,20 @@
 		{Mutator: "version", Variation: version},
 		{Mutator: "link", Variation: "shared"},
 	}, ndkStubDepTag, variantNdkLibs...)
+	actx.AddVariationDependencies([]blueprint.Variation{
+		{Mutator: "version", Variation: version},
+		{Mutator: "link", Variation: "shared"},
+	}, ndkStubDepTag, apiNdkLibs...)
 
 	ndkLateStubDepTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: lateLibraryDependency, ndk: true, makeSuffix: "." + version}
 	actx.AddVariationDependencies([]blueprint.Variation{
 		{Mutator: "version", Variation: version},
 		{Mutator: "link", Variation: "shared"},
 	}, ndkLateStubDepTag, variantLateNdkLibs...)
+	actx.AddVariationDependencies([]blueprint.Variation{
+		{Mutator: "version", Variation: version},
+		{Mutator: "link", Variation: "shared"},
+	}, ndkLateStubDepTag, apiLateNdkLibs...)
 
 	if vndkdep := c.vndkdep; vndkdep != nil {
 		if vndkdep.isVndkExt() {
@@ -2601,6 +2611,10 @@
 		}
 		return
 	}
+	// TODO(b/244244438) : Remove this once all variants are implemented
+	if ccFrom, ok := from.(*Module); ok && ccFrom.isImportedApiLibrary() {
+		return
+	}
 	if from.SdkVersion() == "" {
 		// Platform code can link to anything
 		return
@@ -2627,6 +2641,10 @@
 			// the NDK.
 			return
 		}
+		if c.isImportedApiLibrary() {
+			// Imported library from the API surface is a stub library built against interface definition.
+			return
+		}
 	}
 
 	if strings.HasPrefix(ctx.ModuleName(), "libclang_rt.") && to.Module().Name() == "libc++" {
diff --git a/cc/library_stub.go b/cc/library_stub.go
index 043c03c..22e61a7 100644
--- a/cc/library_stub.go
+++ b/cc/library_stub.go
@@ -15,14 +15,17 @@
 package cc
 
 import (
+	"regexp"
 	"strings"
 
-	"github.com/google/blueprint/proptools"
-
 	"android/soong/android"
 	"android/soong/multitree"
 )
 
+var (
+	ndkVariantRegex = regexp.MustCompile("ndk\\.([a-zA-Z0-9]+)")
+)
+
 func init() {
 	RegisterLibraryStubBuildComponents(android.InitRegistrationContext)
 }
@@ -45,13 +48,17 @@
 	}
 
 	if m.UseVndk() && apiLibrary.hasLLNDKStubs() {
-		// Add LLNDK dependencies
-		for _, variant := range apiLibrary.properties.Variants {
-			if variant == "llndk" {
-				variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
-				ctx.AddDependency(m, nil, variantName)
-				break
-			}
+		// Add LLNDK variant dependency
+		if inList("llndk", apiLibrary.properties.Variants) {
+			variantName := BuildApiVariantName(m.BaseModuleName(), "llndk", "")
+			ctx.AddDependency(m, nil, variantName)
+		}
+	} else if m.IsSdkVariant() {
+		// Add NDK variant dependencies
+		targetVariant := "ndk." + m.StubsVersion()
+		if inList(targetVariant, apiLibrary.properties.Variants) {
+			variantName := BuildApiVariantName(m.BaseModuleName(), targetVariant, "")
+			ctx.AddDependency(m, nil, variantName)
 		}
 	}
 }
@@ -117,12 +124,31 @@
 	}
 }
 
+func (d *apiLibraryDecorator) linkerInit(ctx BaseModuleContext) {
+	d.baseLinker.linkerInit(ctx)
+
+	if d.hasNDKStubs() {
+		// Set SDK version of module as current
+		ctx.Module().(*Module).Properties.Sdk_version = StringPtr("current")
+
+		// Add NDK stub as NDK known libs
+		name := ctx.ModuleName()
+
+		ndkKnownLibsLock.Lock()
+		ndkKnownLibs := getNDKKnownLibs(ctx.Config())
+		if !inList(name, *ndkKnownLibs) {
+			*ndkKnownLibs = append(*ndkKnownLibs, name)
+		}
+		ndkKnownLibsLock.Unlock()
+	}
+}
+
 func (d *apiLibraryDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objects Objects) android.Path {
 	m, _ := ctx.Module().(*Module)
 
 	var in android.Path
 
-	if src := proptools.String(d.properties.Src); src != "" {
+	if src := String(d.properties.Src); src != "" {
 		in = android.PathForModuleSrc(ctx, src)
 	}
 
@@ -149,7 +175,7 @@
 					variantMod.exportProperties.Export_headers...)
 
 				// Export headers as system include dirs if specified. Mostly for libc
-				if proptools.Bool(variantMod.exportProperties.Export_headers_as_system) {
+				if Bool(variantMod.exportProperties.Export_headers_as_system) {
 					d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs = append(
 						d.libraryDecorator.flagExporter.Properties.Export_system_include_dirs,
 						d.libraryDecorator.flagExporter.Properties.Export_include_dirs...)
@@ -157,6 +183,29 @@
 				}
 			}
 		}
+	} else if m.IsSdkVariant() {
+		// NDK Variant
+		apiVariantModule := BuildApiVariantName(m.BaseModuleName(), "ndk", m.StubsVersion())
+
+		var mod android.Module
+
+		ctx.VisitDirectDeps(func(depMod android.Module) {
+			if depMod.Name() == apiVariantModule {
+				mod = depMod
+			}
+		})
+
+		if mod != nil {
+			variantMod, ok := mod.(*CcApiVariant)
+			if ok {
+				in = variantMod.Src()
+
+				// Copy NDK properties to cc_api_library module
+				d.libraryDecorator.flagExporter.Properties.Export_include_dirs = append(
+					d.libraryDecorator.flagExporter.Properties.Export_include_dirs,
+					variantMod.exportProperties.Export_headers...)
+			}
+		}
 	}
 
 	// Flags reexported from dependencies. (e.g. vndk_prebuilt_shared)
@@ -214,6 +263,14 @@
 
 	// TODO(b/244244438) Create more version information for NDK and APEX variations
 	// NDK variants
+
+	if m.IsSdkVariant() {
+		// TODO(b/249193999) Do not check if module has NDK stubs once all NDK cc_api_library contains ndk variant of cc_api_variant.
+		if d.hasNDKStubs() {
+			return d.getNdkVersions()
+		}
+	}
+
 	if m.MinSdkVersion() == "" {
 		return nil
 	}
@@ -229,14 +286,30 @@
 }
 
 func (d *apiLibraryDecorator) hasLLNDKStubs() bool {
+	return inList("llndk", d.properties.Variants)
+}
+
+func (d *apiLibraryDecorator) hasNDKStubs() bool {
 	for _, variant := range d.properties.Variants {
-		if strings.Contains(variant, "llndk") {
+		if ndkVariantRegex.MatchString(variant) {
 			return true
 		}
 	}
 	return false
 }
 
+func (d *apiLibraryDecorator) getNdkVersions() []string {
+	ndkVersions := []string{}
+
+	for _, variant := range d.properties.Variants {
+		if match := ndkVariantRegex.FindStringSubmatch(variant); len(match) == 2 {
+			ndkVersions = append(ndkVersions, match[1])
+		}
+	}
+
+	return ndkVersions
+}
+
 // 'cc_api_headers' is similar with 'cc_api_library', but which replaces
 // header libraries. The module will replace any dependencies to existing
 // original header libraries.
@@ -320,18 +393,18 @@
 func (v *CcApiVariant) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// No need to build
 
-	if proptools.String(v.properties.Src) == "" {
+	if String(v.properties.Src) == "" {
 		ctx.PropertyErrorf("src", "src is a required property")
 	}
 
 	// Skip the existence check of the stub prebuilt file.
 	// The file is not guaranteed to exist during Soong analysis.
 	// Build orchestrator will be responsible for creating a connected ninja graph.
-	v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), proptools.String(v.properties.Src))
+	v.src = android.MaybeExistentPathForSource(ctx, ctx.ModuleDir(), String(v.properties.Src))
 }
 
 func (v *CcApiVariant) Name() string {
-	version := proptools.String(v.properties.Version)
+	version := String(v.properties.Version)
 	return BuildApiVariantName(v.BaseModuleName(), *v.properties.Variant, version)
 }
 
@@ -349,8 +422,10 @@
 }
 
 // Implement ImageInterface to generate image variants
-func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext)               {}
-func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool          { return false }
+func (v *CcApiVariant) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+func (v *CcApiVariant) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+	return String(v.properties.Variant) == "ndk"
+}
 func (v *CcApiVariant) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool       { return false }
 func (v *CcApiVariant) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool { return false }
 func (v *CcApiVariant) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool  { return false }
@@ -359,7 +434,7 @@
 	var variations []string
 	platformVndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
 
-	if proptools.String(v.properties.Variant) == "llndk" {
+	if String(v.properties.Variant) == "llndk" {
 		variations = append(variations, VendorVariationPrefix+platformVndkVersion)
 		variations = append(variations, ProductVariationPrefix+platformVndkVersion)
 	}
diff --git a/cc/library_stub_test.go b/cc/library_stub_test.go
index 8ce74c4..e372860 100644
--- a/cc/library_stub_test.go
+++ b/cc/library_stub_test.go
@@ -322,16 +322,188 @@
 
 	ctx := prepareForCcTest.RunTestWithBp(t, bp)
 
-	libfoo := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Module()
+	binfoo := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Module()
 	libbarApiImport := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
 	libbarApiVariant := ctx.ModuleForTests("libbar.llndk.apiimport", "android_vendor.29_arm64_armv8-a").Module()
 
-	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, libfoo, libbarApiImport))
+	android.AssertBoolEquals(t, "Stub library from API surface should be linked", true, hasDirectDependency(t, ctx, binfoo, libbarApiImport))
 	android.AssertBoolEquals(t, "Stub library variant from API surface should be linked", true, hasDirectDependency(t, ctx, libbarApiImport, libbarApiVariant))
 
-	libFooLibFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("ld").Args["libFlags"]
-	android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", libFooLibFlags, "libbar_llndk.so")
+	binFooLibFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("ld").Args["libFlags"]
+	android.AssertStringDoesContain(t, "Vendor binary should be linked with LLNDK variant source", binFooLibFlags, "libbar_llndk.so")
 
-	libFooCFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"]
-	android.AssertStringDoesContain(t, "Vendor binary should include headers from the LLNDK variant source", libFooCFlags, "-Ilibbar_llndk_include")
+	binFooCFlags := ctx.ModuleForTests("binfoo", "android_vendor.29_arm64_armv8-a").Rule("cc").Args["cFlags"]
+	android.AssertStringDoesContain(t, "Vendor binary should include headers from the LLNDK variant source", binFooCFlags, "-Ilibbar_llndk_include")
+}
+
+func TestApiLibraryWithNdkVariant(t *testing.T) {
+	bp := `
+		cc_binary {
+			name: "binfoo",
+			sdk_version: "29",
+			srcs: ["binfoo.cc"],
+			shared_libs: ["libbar"],
+			stl: "c++_shared",
+		}
+
+		cc_binary {
+			name: "binbaz",
+			sdk_version: "30",
+			srcs: ["binbaz.cc"],
+			shared_libs: ["libbar"],
+			stl: "c++_shared",
+		}
+
+		cc_api_library {
+			name: "libbar",
+			// TODO(b/244244438) Remove src property once all variants are implemented.
+			src: "libbar.so",
+			variants: [
+				"ndk.29",
+				"ndk.30",
+				"ndk.current",
+			],
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "ndk",
+			version: "29",
+			src: "libbar_ndk_29.so",
+			export_headers: ["libbar_ndk_29_include"]
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "ndk",
+			version: "30",
+			src: "libbar_ndk_30.so",
+			export_headers: ["libbar_ndk_30_include"]
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "ndk",
+			version: "current",
+			src: "libbar_ndk_current.so",
+			export_headers: ["libbar_ndk_current_include"]
+		}
+
+		api_imports {
+			name: "api_imports",
+			shared_libs: [
+				"libbar",
+			],
+			header_libs: [],
+		}
+	`
+
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+	binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module()
+	libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module()
+	libbarApiVariantv29 := ctx.ModuleForTests("libbar.ndk.29.apiimport", "android_arm64_armv8-a_sdk").Module()
+	libbarApiImportv30 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_30").Module()
+	libbarApiVariantv30 := ctx.ModuleForTests("libbar.ndk.30.apiimport", "android_arm64_armv8-a_sdk").Module()
+
+	android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29))
+	android.AssertBoolEquals(t, "Stub library variant from API surface should be linked with target version", true, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv29))
+	android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportv30))
+	android.AssertBoolEquals(t, "Stub library variant from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, libbarApiImportv29, libbarApiVariantv30))
+
+	binbaz := ctx.ModuleForTests("binbaz", "android_arm64_armv8-a_sdk").Module()
+
+	android.AssertBoolEquals(t, "Stub library from API surface should be linked with target version", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportv30))
+	android.AssertBoolEquals(t, "Stub library from API surface should not be linked with different version", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29))
+
+	binFooLibFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("ld").Args["libFlags"]
+	android.AssertStringDoesContain(t, "Binary using sdk should be linked with NDK variant source", binFooLibFlags, "libbar_ndk_29.so")
+
+	binFooCFlags := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Rule("cc").Args["cFlags"]
+	android.AssertStringDoesContain(t, "Binary using sdk should include headers from the NDK variant source", binFooCFlags, "-Ilibbar_ndk_29_include")
+}
+
+func TestApiLibraryWithMultipleVariants(t *testing.T) {
+	bp := `
+		cc_binary {
+			name: "binfoo",
+			sdk_version: "29",
+			srcs: ["binfoo.cc"],
+			shared_libs: ["libbar"],
+			stl: "c++_shared",
+		}
+
+		cc_binary {
+			name: "binbaz",
+			vendor: true,
+			srcs: ["binbaz.cc"],
+			shared_libs: ["libbar"],
+		}
+
+		cc_api_library {
+			name: "libbar",
+			// TODO(b/244244438) Remove src property once all variants are implemented.
+			src: "libbar.so",
+			vendor_available: true,
+			variants: [
+				"llndk",
+				"ndk.29",
+				"ndk.30",
+				"ndk.current",
+			],
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "ndk",
+			version: "29",
+			src: "libbar_ndk_29.so",
+			export_headers: ["libbar_ndk_29_include"]
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "ndk",
+			version: "30",
+			src: "libbar_ndk_30.so",
+			export_headers: ["libbar_ndk_30_include"]
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "ndk",
+			version: "current",
+			src: "libbar_ndk_current.so",
+			export_headers: ["libbar_ndk_current_include"]
+		}
+
+		cc_api_variant {
+			name: "libbar",
+			variant: "llndk",
+			src: "libbar_llndk.so",
+			export_headers: ["libbar_llndk_include"]
+		}
+
+		api_imports {
+			name: "api_imports",
+			shared_libs: [
+				"libbar",
+			],
+			header_libs: [],
+		}
+	`
+	ctx := prepareForCcTest.RunTestWithBp(t, bp)
+
+	binfoo := ctx.ModuleForTests("binfoo", "android_arm64_armv8-a_sdk").Module()
+	libbarApiImportv29 := ctx.ModuleForTests("libbar.apiimport", "android_arm64_armv8-a_sdk_shared_29").Module()
+	libbarApiImportLlndk := ctx.ModuleForTests("libbar.apiimport", "android_vendor.29_arm64_armv8-a_shared").Module()
+
+	android.AssertBoolEquals(t, "Binary using SDK should be linked with API library from NDK variant", true, hasDirectDependency(t, ctx, binfoo, libbarApiImportv29))
+	android.AssertBoolEquals(t, "Binary using SDK should not be linked with API library from LLNDK variant", false, hasDirectDependency(t, ctx, binfoo, libbarApiImportLlndk))
+
+	binbaz := ctx.ModuleForTests("binbaz", "android_vendor.29_arm64_armv8-a").Module()
+
+	android.AssertBoolEquals(t, "Vendor binary should be linked with API library from LLNDK variant", true, hasDirectDependency(t, ctx, binbaz, libbarApiImportLlndk))
+	android.AssertBoolEquals(t, "Vendor binary should not be linked with API library from NDK variant", false, hasDirectDependency(t, ctx, binbaz, libbarApiImportv29))
+
 }
diff --git a/cc/sdk.go b/cc/sdk.go
index a0d196b..3e50c9f 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -31,6 +31,7 @@
 
 	switch m := ctx.Module().(type) {
 	case LinkableInterface:
+		ccModule, isCcModule := ctx.Module().(*Module)
 		if m.AlwaysSdk() {
 			if !m.UseSdk() && !m.SplitPerApiLevel() {
 				ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
@@ -58,11 +59,32 @@
 				modules[1].(*Module).Properties.PreventInstall = true
 			}
 			ctx.AliasVariation("")
+		} else if isCcModule && ccModule.isImportedApiLibrary() {
+			apiLibrary, _ := ccModule.linker.(*apiLibraryDecorator)
+			if apiLibrary.hasNDKStubs() && ccModule.canUseSdk() {
+				// Handle cc_api_library module with NDK stubs and variants only which can use SDK
+				modules := ctx.CreateVariations("", "sdk")
+				modules[1].(*Module).Properties.IsSdkVariant = true
+				if ctx.Config().UnbundledBuildApps() {
+					// For an unbundled apps build, hide the platform variant from Make.
+					modules[0].(*Module).Properties.HideFromMake = true
+					modules[0].(*Module).Properties.PreventInstall = true
+				} else {
+					// For a platform build, mark the SDK variant so that it gets a ".sdk" suffix when
+					// exposed to Make.
+					modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
+					modules[1].(*Module).Properties.PreventInstall = true
+				}
+			} else {
+				ccModule.Properties.Sdk_version = nil
+				ctx.CreateVariations("")
+				ctx.AliasVariation("")
+			}
 		} else {
-			if m, ok := ctx.Module().(*Module); ok {
+			if isCcModule {
 				// Clear the sdk_version property for modules that don't have an SDK variant so
 				// later code doesn't get confused by it.
-				m.Properties.Sdk_version = nil
+				ccModule.Properties.Sdk_version = nil
 			}
 			ctx.CreateVariations("")
 			ctx.AliasVariation("")
@@ -79,6 +101,11 @@
 	case *snapshotModule:
 		ctx.CreateVariations("")
 	case *CcApiVariant:
-		ctx.CreateVariations("")
+		ccApiVariant, _ := ctx.Module().(*CcApiVariant)
+		if String(ccApiVariant.properties.Variant) == "ndk" {
+			ctx.CreateVariations("sdk")
+		} else {
+			ctx.CreateVariations("")
+		}
 	}
 }