Support using cc_prebuilt_library_shared with cc_library

Allow a cc_prebuilt_library_shared to share the same name as a
cc_library by always creating static and shared variants of
prebuilts so that the variants of the source module are always
a superset of the variants of the target module.

Bug: 131709055
Test: TestPrebuilts
Change-Id: I4afd6d37e6a986d08ad25aee69eca6d994febc6b
diff --git a/Android.bp b/Android.bp
index e2d606e..c9a48b4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -196,6 +196,7 @@
         "cc/gen_test.go",
         "cc/genrule_test.go",
         "cc/library_test.go",
+        "cc/prebuilt_test.go",
         "cc/proto_test.go",
         "cc/test_data_test.go",
         "cc/util_test.go",
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 36d8aa4..ef6364b 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -52,7 +52,9 @@
 	os.Exit(run())
 }
 
-func createTestContext(t *testing.T, config android.Config, bp string, os android.OsType) *android.TestContext {
+func createTestContext(t *testing.T, config android.Config, bp string, fs map[string][]byte,
+	os android.OsType) *android.TestContext {
+
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
 	ctx.RegisterModuleType("cc_binary_host", android.ModuleFactoryAdaptor(binaryHostFactory))
@@ -77,12 +79,11 @@
 		ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
 	})
 	ctx.RegisterSingletonType("vndk-snapshot", android.SingletonFactoryAdaptor(VndkSnapshotSingleton))
-	ctx.Register()
 
 	// add some modules that are required by the compiler and/or linker
 	bp = bp + GatherRequiredDepsForTest(os)
 
-	ctx.MockFileSystem(map[string][]byte{
+	mockFS := map[string][]byte{
 		"Android.bp":  []byte(bp),
 		"foo.c":       nil,
 		"bar.c":       nil,
@@ -90,7 +91,14 @@
 		"b.aidl":      nil,
 		"my_include":  nil,
 		"foo.map.txt": nil,
-	})
+		"liba.so":     nil,
+	}
+
+	for k, v := range fs {
+		mockFS[k] = v
+	}
+
+	ctx.MockFileSystem(mockFS)
 
 	return ctx
 }
@@ -101,7 +109,8 @@
 
 func testCcWithConfigForOs(t *testing.T, bp string, config android.Config, os android.OsType) *android.TestContext {
 	t.Helper()
-	ctx := createTestContext(t, config, bp, os)
+	ctx := createTestContext(t, config, bp, nil, os)
+	ctx.Register()
 
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	android.FailIfErrored(t, errs)
@@ -134,7 +143,8 @@
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
 	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
 
-	ctx := createTestContext(t, config, bp, android.Android)
+	ctx := createTestContext(t, config, bp, nil, android.Android)
+	ctx.Register()
 
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
 	if len(errs) > 0 {
diff --git a/cc/library.go b/cc/library.go
index c2ab098..11c1d90 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -23,7 +23,6 @@
 	"strings"
 	"sync"
 
-	"github.com/google/blueprint"
 	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
@@ -1106,10 +1105,28 @@
 
 func LinkageMutator(mctx android.BottomUpMutatorContext) {
 	if m, ok := mctx.Module().(*Module); ok && m.linker != nil {
-		if library, ok := m.linker.(libraryInterface); ok {
-			var modules []blueprint.Module
+		switch library := m.linker.(type) {
+		case prebuiltLibraryInterface:
+			// Always create both the static and shared variants for prebuilt libraries, and then disable the one
+			// that is not being used.  This allows them to share the name of a cc_library module, which requires that
+			// all the variants of the cc_library also exist on the prebuilt.
+			modules := mctx.CreateLocalVariations("static", "shared")
+			static := modules[0].(*Module)
+			shared := modules[1].(*Module)
+
+			static.linker.(prebuiltLibraryInterface).setStatic()
+			shared.linker.(prebuiltLibraryInterface).setShared()
+
+			if !library.buildStatic() {
+				static.linker.(prebuiltLibraryInterface).disablePrebuilt()
+			}
+			if !library.buildShared() {
+				shared.linker.(prebuiltLibraryInterface).disablePrebuilt()
+			}
+
+		case libraryInterface:
 			if library.buildStatic() && library.buildShared() {
-				modules = mctx.CreateLocalVariations("static", "shared")
+				modules := mctx.CreateLocalVariations("static", "shared")
 				static := modules[0].(*Module)
 				shared := modules[1].(*Module)
 
@@ -1119,10 +1136,10 @@
 				reuseStaticLibrary(mctx, static, shared)
 
 			} else if library.buildStatic() {
-				modules = mctx.CreateLocalVariations("static")
+				modules := mctx.CreateLocalVariations("static")
 				modules[0].(*Module).linker.(libraryInterface).setStatic()
 			} else if library.buildShared() {
-				modules = mctx.CreateLocalVariations("shared")
+				modules := mctx.CreateLocalVariations("shared")
 				modules[0].(*Module).linker.(libraryInterface).setShared()
 			}
 		}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 5ffeb32..48e4667 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -53,12 +53,19 @@
 	return p.properties.Srcs
 }
 
+type prebuiltLibraryInterface interface {
+	libraryInterface
+	prebuiltLinkerInterface
+	disablePrebuilt()
+}
+
 type prebuiltLibraryLinker struct {
 	*libraryDecorator
 	prebuiltLinker
 }
 
 var _ prebuiltLinkerInterface = (*prebuiltLibraryLinker)(nil)
+var _ prebuiltLibraryInterface = (*prebuiltLibraryLinker)(nil)
 
 func (p *prebuiltLibraryLinker) linkerInit(ctx BaseModuleContext) {}
 
@@ -116,6 +123,10 @@
 	return false
 }
 
+func (p *prebuiltLibraryLinker) disablePrebuilt() {
+	p.properties.Srcs = nil
+}
+
 // cc_prebuilt_library_shared installs a precompiled shared library that are
 // listed in the srcs property in the device's directory.
 func prebuiltSharedLibraryFactory() android.Module {
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
new file mode 100644
index 0000000..7cc2651
--- /dev/null
+++ b/cc/prebuilt_test.go
@@ -0,0 +1,126 @@
+// Copyright 2019 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 cc
+
+import (
+	"testing"
+
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+func TestPrebuilt(t *testing.T) {
+	bp := `
+		cc_library {
+			name: "liba",
+		}
+
+		cc_prebuilt_library_shared {
+			name: "liba",
+			srcs: ["liba.so"],
+		}
+
+		cc_library {
+			name: "libb",
+		}
+
+		cc_prebuilt_library_static {
+			name: "libb",
+			srcs: ["libb.a"],
+		}
+
+		cc_library_shared {
+			name: "libd",
+		}
+
+		cc_prebuilt_library_shared {
+			name: "libd",
+			srcs: ["libd.so"],
+		}
+
+		cc_library_static {
+			name: "libe",
+		}
+
+		cc_prebuilt_library_static {
+			name: "libe",
+			srcs: ["libe.a"],
+		}
+	`
+
+	fs := map[string][]byte{
+		"liba.so": nil,
+		"libb.a":  nil,
+		"libd.so": nil,
+		"libe.a":  nil,
+	}
+
+	config := android.TestArchConfig(buildDir, nil)
+
+	ctx := createTestContext(t, config, bp, fs, android.Android)
+
+	ctx.RegisterModuleType("cc_prebuilt_library_shared", android.ModuleFactoryAdaptor(prebuiltSharedLibraryFactory))
+	ctx.RegisterModuleType("cc_prebuilt_library_static", android.ModuleFactoryAdaptor(prebuiltStaticLibraryFactory))
+	ctx.RegisterModuleType("cc_prebuilt_binary", android.ModuleFactoryAdaptor(prebuiltBinaryFactory))
+
+	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
+	ctx.PostDepsMutators(android.RegisterPrebuiltsPostDepsMutators)
+
+	ctx.Register()
+
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	// Verify that all the modules exist and that their dependencies were connected correctly
+	liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_core_shared").Module()
+	libb := ctx.ModuleForTests("libb", "android_arm64_armv8-a_core_static").Module()
+	libd := ctx.ModuleForTests("libd", "android_arm64_armv8-a_core_shared").Module()
+	libe := ctx.ModuleForTests("libe", "android_arm64_armv8-a_core_static").Module()
+
+	prebuiltLiba := ctx.ModuleForTests("prebuilt_liba", "android_arm64_armv8-a_core_shared").Module()
+	prebuiltLibb := ctx.ModuleForTests("prebuilt_libb", "android_arm64_armv8-a_core_static").Module()
+	prebuiltLibd := ctx.ModuleForTests("prebuilt_libd", "android_arm64_armv8-a_core_shared").Module()
+	prebuiltLibe := ctx.ModuleForTests("prebuilt_libe", "android_arm64_armv8-a_core_static").Module()
+
+	hasDep := func(m android.Module, wantDep android.Module) bool {
+		t.Helper()
+		var found bool
+		ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+			if dep == wantDep {
+				found = true
+			}
+		})
+		return found
+	}
+
+	if !hasDep(liba, prebuiltLiba) {
+		t.Errorf("liba missing dependency on prebuilt_liba")
+	}
+
+	if !hasDep(libb, prebuiltLibb) {
+		t.Errorf("libb missing dependency on prebuilt_libb")
+	}
+
+	if !hasDep(libd, prebuiltLibd) {
+		t.Errorf("libd missing dependency on prebuilt_libd")
+	}
+
+	if !hasDep(libe, prebuiltLibe) {
+		t.Errorf("libe missing dependency on prebuilt_libe")
+	}
+}