Merge "Allow platform modules to link to vendor public libraries"
diff --git a/Android.bp b/Android.bp
index 9162926..ec69df8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -163,6 +163,8 @@
         "cc/kernel_headers.go",
 
         "cc/genrule.go",
+
+        "cc/vendor_public_library.go",
     ],
     testSrcs: [
         "cc/cc_test.go",
diff --git a/android/makevars.go b/android/makevars.go
index 00a20f5..b6cd571 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -36,6 +36,7 @@
 // Interface for other packages to use to declare make variables
 type MakeVarsContext interface {
 	Config() Config
+	SingletonContext() SingletonContext
 
 	// Verify the make variable matches the Soong version, fail the build
 	// if it does not. If the make variable is empty, just set it.
@@ -230,6 +231,10 @@
 	return c.config
 }
 
+func (c *makeVarsContext) SingletonContext() SingletonContext {
+	return c.ctx
+}
+
 func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
 	return c.ctx.Eval(c.pctx, ninjaStr)
 }
diff --git a/android/module.go b/android/module.go
index 4a8e8ac..1e54470 100644
--- a/android/module.go
+++ b/android/module.go
@@ -177,6 +177,7 @@
 	InstallInData() bool
 	InstallInSanitizerDir() bool
 	SkipInstall()
+	ExportedToMake() bool
 
 	AddProperties(props ...interface{})
 	GetProperties() []interface{}
@@ -507,6 +508,10 @@
 	a.commonProperties.SkipInstall = true
 }
 
+func (a *ModuleBase) ExportedToMake() bool {
+	return a.commonProperties.NamespaceExportedToMake
+}
+
 func (a *ModuleBase) computeInstallDeps(
 	ctx blueprint.ModuleContext) Paths {
 
diff --git a/cc/androidmk.go b/cc/androidmk.go
index e78c419..56ff713 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -383,3 +383,18 @@
 		fmt.Fprintln(w, "LOCAL_COPY_TO_INTERMEDIATE_LIBRARIES := false")
 	})
 }
+
+func (c *vendorPublicLibraryStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+	ret.Class = "SHARED_LIBRARIES"
+	ret.SubName = vendorPublicLibrarySuffix
+
+	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+		c.libraryDecorator.androidMkWriteExportedFlags(w)
+
+		fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+outputFile.Ext())
+		fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false")
+		fmt.Fprintln(w, "LOCAL_SYSTEM_SHARED_LIBRARIES :=")
+		fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+		fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true")
+	})
+}
diff --git a/cc/cc.go b/cc/cc.go
index 721f4b1..e91711e 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -922,6 +922,16 @@
 					}
 				} else if ctx.useVndk() && inList(entry, llndkLibraries) {
 					nonvariantLibs = append(nonvariantLibs, entry+llndkLibrarySuffix)
+				} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(entry, vendorPublicLibraries) {
+					vendorPublicLib := entry + vendorPublicLibrarySuffix
+					if actx.OtherModuleExists(vendorPublicLib) {
+						nonvariantLibs = append(nonvariantLibs, vendorPublicLib)
+					} else {
+						// This can happen if vendor_public_library module is defined in a
+						// namespace that isn't visible to the current module. In that case,
+						// link to the original library.
+						nonvariantLibs = append(nonvariantLibs, entry)
+					}
 				} else {
 					nonvariantLibs = append(nonvariantLibs, entry)
 				}
@@ -1306,14 +1316,18 @@
 		switch depTag {
 		case sharedDepTag, sharedExportDepTag, lateSharedDepTag:
 			libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
+			libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
 			libName = strings.TrimPrefix(libName, "prebuilt_")
 			isLLndk := inList(libName, llndkLibraries)
+			isVendorPublicLib := inList(libName, vendorPublicLibraries)
 			var makeLibName string
 			bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
 			if c.useVndk() && bothVendorAndCoreVariantsExist {
 				// The vendor module in Make will have been renamed to not conflict with the core
 				// module, so update the dependency name here accordingly.
 				makeLibName = libName + vendorSuffix
+			} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
+				makeLibName = libName + vendorPublicLibrarySuffix
 			} else {
 				makeLibName = libName
 			}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 437211c..75aa290 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -56,15 +56,18 @@
 	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
 	ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
+	ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
 	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(toolchainLibraryFactory))
 	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(llndkLibraryFactory))
 	ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory))
+	ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory))
 	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(objectFactory))
 	ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(genrule.FileGroupFactory))
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("image", vendorMutator).Parallel()
 		ctx.BottomUp("link", linkageMutator).Parallel()
 		ctx.BottomUp("vndk", vndkMutator).Parallel()
+		ctx.BottomUp("begin", beginMutator).Parallel()
 	})
 	ctx.Register()
 
@@ -115,6 +118,34 @@
 			name: "libdl",
 			symbol_file: "",
 		}
+		cc_library {
+			name: "libc++_static",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+			vendor_available: true,
+		}
+		cc_library {
+			name: "libc++",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+				support_system_process: true,
+			},
+		}
+		cc_library {
+			name: "libunwind_llvm",
+			no_libgcc: true,
+			nocrt: true,
+			system_shared_libs: [],
+			stl: "none",
+			vendor_available: true,
+		}
 
 		cc_object {
 			name: "crtbegin_so",
@@ -1077,16 +1108,20 @@
 	cc_library {
 		name: "a",
 		static_libs: ["b", "c", "d"],
+		stl: "none",
 	}
 	cc_library {
 		name: "b",
+		stl: "none",
 	}
 	cc_library {
 		name: "c",
 		static_libs: ["b"],
+		stl: "none",
 	}
 	cc_library {
 		name: "d",
+		stl: "none",
 	}
 
 	`)
@@ -1111,13 +1146,16 @@
 	cc_library {
 		name: "a",
 		static_libs: ["b", "c"],
+		stl: "none",
 	}
 	cc_library {
 		name: "b",
+		stl: "none",
 	}
 	cc_library {
 		name: "c",
 		shared_libs: ["b"],
+		stl: "none",
 	}
 
 	`)
@@ -1249,3 +1287,68 @@
 		}
 	}
 }
+
+func TestVendorPublicLibraries(t *testing.T) {
+	ctx := testCc(t, `
+	cc_library_headers {
+		name: "libvendorpublic_headers",
+		export_include_dirs: ["my_include"],
+	}
+	vendor_public_library {
+		name: "libvendorpublic",
+		symbol_file: "",
+		export_public_headers: ["libvendorpublic_headers"],
+	}
+	cc_library {
+		name: "libvendorpublic",
+		srcs: ["foo.c"],
+		vendor: true,
+		no_libgcc: true,
+		nocrt: true,
+	}
+
+	cc_library {
+		name: "libsystem",
+		shared_libs: ["libvendorpublic"],
+		vendor: false,
+		srcs: ["foo.c"],
+		no_libgcc: true,
+		nocrt: true,
+	}
+	cc_library {
+		name: "libvendor",
+		shared_libs: ["libvendorpublic"],
+		vendor: true,
+		srcs: ["foo.c"],
+		no_libgcc: true,
+		nocrt: true,
+	}
+	`)
+
+	variant := "android_arm64_armv8-a_core_shared"
+
+	// test if header search paths are correctly added
+	// _static variant is used since _shared reuses *.o from the static variant
+	cc := ctx.ModuleForTests("libsystem", strings.Replace(variant, "_shared", "_static", 1)).Rule("cc")
+	cflags := cc.Args["cFlags"]
+	if !strings.Contains(cflags, "-Imy_include") {
+		t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags)
+	}
+
+	// test if libsystem is linked to the stub
+	ld := ctx.ModuleForTests("libsystem", variant).Rule("ld")
+	libflags := ld.Args["libFlags"]
+	stubPaths := getOutputPaths(ctx, variant, []string{"libvendorpublic" + vendorPublicLibrarySuffix})
+	if !strings.Contains(libflags, stubPaths[0].String()) {
+		t.Errorf("libflags for libsystem must contain %#v, but was %#v", stubPaths[0], libflags)
+	}
+
+	// test if libvendor is linked to the real shared lib
+	ld = ctx.ModuleForTests("libvendor", strings.Replace(variant, "_core", "_vendor", 1)).Rule("ld")
+	libflags = ld.Args["libFlags"]
+	stubPaths = getOutputPaths(ctx, strings.Replace(variant, "_core", "_vendor", 1), []string{"libvendorpublic"})
+	if !strings.Contains(libflags, stubPaths[0].String()) {
+		t.Errorf("libflags for libvendor must contain %#v, but was %#v", stubPaths[0], libflags)
+	}
+
+}
diff --git a/cc/makevars.go b/cc/makevars.go
index 042af2a..2664ee1 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -100,6 +100,21 @@
 	ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " "))
 	ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " "))
 
+	// Filter vendor_public_library that are exported to make
+	exportedVendorPublicLibraries := []string{}
+	ctx.SingletonContext().VisitAllModules(func(module android.Module) {
+		if ccModule, ok := module.(*Module); ok {
+			baseName := ccModule.BaseModuleName()
+			if inList(baseName, vendorPublicLibraries) && module.ExportedToMake() {
+				if !inList(baseName, exportedVendorPublicLibraries) {
+					exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName)
+				}
+			}
+		}
+	})
+	sort.Strings(exportedVendorPublicLibraries)
+	ctx.Strict("VENDOR_PUBLIC_LIBRARIES", strings.Join(exportedVendorPublicLibraries, " "))
+
 	sort.Strings(lsdumpPaths)
 	ctx.Strict("LSDUMP_PATHS", strings.Join(lsdumpPaths, " "))
 
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
new file mode 100644
index 0000000..da41cbc
--- /dev/null
+++ b/cc/vendor_public_library.go
@@ -0,0 +1,150 @@
+// Copyright 2018 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 (
+	"strings"
+	"sync"
+
+	"android/soong/android"
+)
+
+var (
+	vendorPublicLibrarySuffix = ".vendorpublic"
+
+	vendorPublicLibraries     = []string{}
+	vendorPublicLibrariesLock sync.Mutex
+)
+
+// Creates a stub shared library for a vendor public library. Vendor public libraries
+// are vendor libraries (owned by them and installed to /vendor partition) that are
+// exposed to Android apps via JNI. The libraries are made public by being listed in
+// /vendor/etc/public.libraries.txt.
+//
+// This stub library is a build-time only artifact that provides symbols that are
+// exposed from a vendor public library.
+//
+// Example:
+//
+// vendor_public_library {
+//     name: "libfoo",
+//     symbol_file: "libfoo.map.txt",
+//     export_public_headers: ["libfoo_headers"],
+// }
+//
+// cc_headers {
+//     name: "libfoo_headers",
+//     export_include_dirs: ["include"],
+// }
+//
+type vendorPublicLibraryProperties struct {
+	// Relative path to the symbol map.
+	Symbol_file *string
+
+	// Whether the system library uses symbol versions.
+	Unversioned *bool
+
+	// list of header libs to re-export include directories from.
+	Export_public_headers []string `android:"arch_variant"`
+}
+
+type vendorPublicLibraryStubDecorator struct {
+	*libraryDecorator
+
+	Properties vendorPublicLibraryProperties
+
+	versionScriptPath android.ModuleGenPath
+}
+
+func (stub *vendorPublicLibraryStubDecorator) Name(name string) string {
+	return name + vendorPublicLibrarySuffix
+}
+
+func (stub *vendorPublicLibraryStubDecorator) compilerInit(ctx BaseModuleContext) {
+	stub.baseCompiler.compilerInit(ctx)
+
+	name := ctx.baseModuleName()
+	if strings.HasSuffix(name, vendorPublicLibrarySuffix) {
+		ctx.PropertyErrorf("name", "Do not append %q manually, just use the base name", vendorPublicLibrarySuffix)
+	}
+
+	vendorPublicLibrariesLock.Lock()
+	defer vendorPublicLibrariesLock.Unlock()
+	for _, lib := range vendorPublicLibraries {
+		if lib == name {
+			return
+		}
+	}
+	vendorPublicLibraries = append(vendorPublicLibraries, name)
+}
+
+func (stub *vendorPublicLibraryStubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
+	flags = stub.baseCompiler.compilerFlags(ctx, flags, deps)
+	return addStubLibraryCompilerFlags(flags)
+}
+
+func (stub *vendorPublicLibraryStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
+	objs, versionScript := compileStubLibrary(ctx, flags, String(stub.Properties.Symbol_file), "current", "")
+	stub.versionScriptPath = versionScript
+	return objs
+}
+
+func (stub *vendorPublicLibraryStubDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
+	headers := stub.Properties.Export_public_headers
+	deps.HeaderLibs = append(deps.HeaderLibs, headers...)
+	deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders, headers...)
+	return deps
+}
+
+func (stub *vendorPublicLibraryStubDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
+	stub.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), vendorPublicLibrarySuffix)
+	return stub.libraryDecorator.linkerFlags(ctx, flags)
+}
+
+func (stub *vendorPublicLibraryStubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps,
+	objs Objects) android.Path {
+	if !Bool(stub.Properties.Unversioned) {
+		linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String()
+		flags.LdFlags = append(flags.LdFlags, linkerScriptFlag)
+	}
+	return stub.libraryDecorator.link(ctx, flags, deps, objs)
+}
+
+func vendorPublicLibraryFactory() android.Module {
+	module, library := NewLibrary(android.DeviceSupported)
+	library.BuildOnlyShared()
+	module.stl = nil
+	module.sanitize = nil
+	library.StripProperties.Strip.None = BoolPtr(true)
+
+	stub := &vendorPublicLibraryStubDecorator{
+		libraryDecorator: library,
+	}
+	module.compiler = stub
+	module.linker = stub
+	module.installer = nil
+
+	module.AddProperties(
+		&stub.Properties,
+		&library.MutatedProperties,
+		&library.flagExporter.Properties)
+
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
+	return module
+}
+
+func init() {
+	android.RegisterModuleType("vendor_public_library", vendorPublicLibraryFactory)
+}