Create sysprop_library soong module

A newly introduced sysprop_library soong module will generate a
java_sdk_library and a cc_library from .sysprop description files.
Both Java modules and C++ modules can link against sysprop_library
module, thus giving consistency for using generated sysprop API.

As Java controls accessibility of Internal / System properties with
@hide and @SystemApi, 2 different header files will be created. And
build system will selectively expose depending on the property owner
and the place where the client libraries go into.

Bug: 80125326
Bug: 122170616
Test: 1) Create sysprop_library module.
Test: 2) Create empty txt files under prebuilts/sdk.
Test: 3) Create api directory, make update-api, and see changes.
Test: 4) Try to link against sysprop_library with various clients.
Test: 5) Soc_specific, Device_specific, Product_specific, recovery flags
work as intended.
Change-Id: I78dc5780ccfbb4b69e5c61dec26b94e92d43c333
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
new file mode 100644
index 0000000..92e0af4
--- /dev/null
+++ b/sysprop/sysprop_test.go
@@ -0,0 +1,380 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// 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 sysprop
+
+import (
+	"android/soong/android"
+	"android/soong/cc"
+	"android/soong/java"
+
+	"fmt"
+	"io/ioutil"
+	"os"
+	"strings"
+	"testing"
+
+	"github.com/google/blueprint/proptools"
+)
+
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_sysprop_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
+
+func testContext(config android.Config, bp string,
+	fs map[string][]byte) *android.TestContext {
+
+	ctx := android.NewTestArchContext()
+	ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(java.AndroidAppFactory))
+	ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(java.ExportedDroiddocDirFactory))
+	ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
+	ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(java.SystemModulesFactory))
+	ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(java.PrebuiltApisFactory))
+	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("load_hooks", android.LoadHookMutator).Parallel()
+	})
+	ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
+	ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
+	ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+	ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.TopDown("prebuilt_apis", java.PrebuiltApisMutator).Parallel()
+		ctx.TopDown("java_sdk_library", java.SdkLibraryMutator).Parallel()
+	})
+
+	ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+	ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+	ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
+	ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
+	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+		ctx.BottomUp("image", cc.ImageMutator).Parallel()
+		ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+		ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
+		ctx.BottomUp("version", cc.VersionMutator).Parallel()
+		ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+		ctx.BottomUp("sysprop", cc.SyspropMutator).Parallel()
+	})
+
+	ctx.RegisterModuleType("sysprop_library", android.ModuleFactoryAdaptor(syspropLibraryFactory))
+
+	ctx.Register()
+
+	extraModules := []string{
+		"core-lambda-stubs",
+		"framework",
+		"ext",
+		"updatable_media_stubs",
+
+		"android_stubs_current",
+		"android_system_stubs_current",
+		"android_test_stubs_current",
+		"core.current.stubs",
+		"core.platform.api.stubs",
+	}
+
+	for _, extra := range extraModules {
+		bp += fmt.Sprintf(`
+			java_library {
+				name: "%s",
+				srcs: ["a.java"],
+				no_standard_libs: true,
+				sdk_version: "core_current",
+				system_modules: "core-platform-api-stubs-system-modules",
+			}
+		`, extra)
+	}
+
+	bp += `
+		android_app {
+			name: "framework-res",
+			no_framework_libs: true,
+		}
+	`
+
+	systemModules := []string{
+		"core-system-modules",
+		"core-platform-api-stubs-system-modules",
+		"android_stubs_current_system_modules",
+		"android_system_stubs_current_system_modules",
+		"android_test_stubs_current_system_modules",
+	}
+
+	for _, extra := range systemModules {
+		bp += fmt.Sprintf(`
+			java_system_modules {
+				name: "%s",
+			}
+		`, extra)
+	}
+
+	bp += cc.GatherRequiredDepsForTest(android.Android)
+
+	mockFS := map[string][]byte{
+		"Android.bp":             []byte(bp),
+		"a.java":                 nil,
+		"b.java":                 nil,
+		"c.java":                 nil,
+		"d.cpp":                  nil,
+		"api/current.txt":        nil,
+		"api/removed.txt":        nil,
+		"api/system-current.txt": nil,
+		"api/system-removed.txt": nil,
+		"api/test-current.txt":   nil,
+		"api/test-removed.txt":   nil,
+
+		"prebuilts/sdk/current/core/android.jar":                              nil,
+		"prebuilts/sdk/current/public/android.jar":                            nil,
+		"prebuilts/sdk/current/public/framework.aidl":                         nil,
+		"prebuilts/sdk/current/public/core.jar":                               nil,
+		"prebuilts/sdk/current/system/android.jar":                            nil,
+		"prebuilts/sdk/current/test/android.jar":                              nil,
+		"prebuilts/sdk/28/public/api/sysprop-platform.txt":                    nil,
+		"prebuilts/sdk/28/system/api/sysprop-platform.txt":                    nil,
+		"prebuilts/sdk/28/test/api/sysprop-platform.txt":                      nil,
+		"prebuilts/sdk/28/public/api/sysprop-platform-removed.txt":            nil,
+		"prebuilts/sdk/28/system/api/sysprop-platform-removed.txt":            nil,
+		"prebuilts/sdk/28/test/api/sysprop-platform-removed.txt":              nil,
+		"prebuilts/sdk/28/public/api/sysprop-platform-on-product.txt":         nil,
+		"prebuilts/sdk/28/system/api/sysprop-platform-on-product.txt":         nil,
+		"prebuilts/sdk/28/test/api/sysprop-platform-on-product.txt":           nil,
+		"prebuilts/sdk/28/public/api/sysprop-platform-on-product-removed.txt": nil,
+		"prebuilts/sdk/28/system/api/sysprop-platform-on-product-removed.txt": nil,
+		"prebuilts/sdk/28/test/api/sysprop-platform-on-product-removed.txt":   nil,
+		"prebuilts/sdk/28/public/api/sysprop-vendor.txt":                      nil,
+		"prebuilts/sdk/28/system/api/sysprop-vendor.txt":                      nil,
+		"prebuilts/sdk/28/test/api/sysprop-vendor.txt":                        nil,
+		"prebuilts/sdk/28/public/api/sysprop-vendor-removed.txt":              nil,
+		"prebuilts/sdk/28/system/api/sysprop-vendor-removed.txt":              nil,
+		"prebuilts/sdk/28/test/api/sysprop-vendor-removed.txt":                nil,
+		"prebuilts/sdk/tools/core-lambda-stubs.jar":                           nil,
+		"prebuilts/sdk/Android.bp":                                            []byte(`prebuilt_apis { name: "sdk", api_dirs: ["28", "current"],}`),
+
+		// For framework-res, which is an implicit dependency for framework
+		"AndroidManifest.xml":                   nil,
+		"build/target/product/security/testkey": nil,
+
+		"build/soong/scripts/jar-wrapper.sh": nil,
+
+		"build/make/core/proguard.flags":             nil,
+		"build/make/core/proguard_basic_keeps.flags": nil,
+
+		"jdk8/jre/lib/jce.jar": nil,
+		"jdk8/jre/lib/rt.jar":  nil,
+		"jdk8/lib/tools.jar":   nil,
+
+		"bar-doc/a.java":                 nil,
+		"bar-doc/b.java":                 nil,
+		"bar-doc/IFoo.aidl":              nil,
+		"bar-doc/known_oj_tags.txt":      nil,
+		"external/doclava/templates-sdk": nil,
+
+		"cert/new_cert.x509.pem": nil,
+		"cert/new_cert.pk8":      nil,
+
+		"android/sysprop/PlatformProperties.sysprop": nil,
+		"com/android/VendorProperties.sysprop":       nil,
+	}
+
+	for k, v := range fs {
+		mockFS[k] = v
+	}
+
+	ctx.MockFileSystem(mockFS)
+
+	return ctx
+}
+
+func run(t *testing.T, ctx *android.TestContext, config android.Config) {
+	t.Helper()
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp", "prebuilts/sdk/Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+}
+
+func testConfig(env map[string]string) android.Config {
+	if env == nil {
+		env = make(map[string]string)
+	}
+	if env["ANDROID_JAVA8_HOME"] == "" {
+		env["ANDROID_JAVA8_HOME"] = "jdk8"
+	}
+	config := android.TestArchConfig(buildDir, env)
+	config.TestProductVariables.DeviceSystemSdkVersions = []string{"28"}
+	config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
+	return config
+
+}
+
+func test(t *testing.T, bp string) *android.TestContext {
+	t.Helper()
+	config := testConfig(nil)
+	ctx := testContext(config, bp, nil)
+	run(t, ctx, config)
+
+	return ctx
+}
+
+func TestSyspropLibrary(t *testing.T) {
+	ctx := test(t, `
+		sysprop_library {
+			name: "sysprop-platform",
+			srcs: ["android/sysprop/PlatformProperties.sysprop"],
+			api_packages: ["android.sysprop"],
+			property_owner: "Platform",
+			vendor_available: true,
+		}
+
+		sysprop_library {
+			name: "sysprop-platform-on-product",
+			srcs: ["android/sysprop/PlatformProperties.sysprop"],
+			api_packages: ["android.sysprop"],
+			property_owner: "Platform",
+			product_specific: true,
+		}
+
+		sysprop_library {
+			name: "sysprop-vendor",
+			srcs: ["com/android/VendorProperties.sysprop"],
+			api_packages: ["com.android"],
+			property_owner: "Vendor",
+			product_specific: true,
+			vendor_available: true,
+		}
+
+		java_library {
+			name: "java-platform",
+			srcs: ["c.java"],
+			sdk_version: "system_current",
+			libs: ["sysprop-platform"],
+		}
+
+		java_library {
+			name: "java-product",
+			srcs: ["c.java"],
+			sdk_version: "system_current",
+			product_specific: true,
+			libs: ["sysprop-platform", "sysprop-vendor"],
+		}
+
+		java_library {
+			name: "java-vendor",
+			srcs: ["c.java"],
+			sdk_version: "system_current",
+			soc_specific: true,
+			libs: ["sysprop-platform", "sysprop-vendor"],
+		}
+
+		cc_library {
+			name: "cc-client-platform",
+			srcs: ["d.cpp"],
+			static_libs: ["sysprop-platform"],
+		}
+
+		cc_library {
+			name: "cc-client-product",
+			srcs: ["d.cpp"],
+			product_specific: true,
+			static_libs: ["sysprop-platform-on-product", "sysprop-vendor"],
+		}
+
+		cc_library {
+			name: "cc-client-vendor",
+			srcs: ["d.cpp"],
+			soc_specific: true,
+			static_libs: ["sysprop-platform", "sysprop-vendor"],
+		}
+		`)
+
+	for _, variant := range []string{
+		"android_arm_armv7-a-neon_core_shared",
+		"android_arm_armv7-a-neon_core_static",
+		"android_arm_armv7-a-neon_vendor_shared",
+		"android_arm_armv7-a-neon_vendor_static",
+		"android_arm64_armv8-a_core_shared",
+		"android_arm64_armv8-a_core_static",
+		"android_arm64_armv8-a_vendor_shared",
+		"android_arm64_armv8-a_vendor_static",
+	} {
+		// Check for generated cc_library
+		ctx.ModuleForTests("libsysprop-platform", variant)
+		ctx.ModuleForTests("libsysprop-vendor", variant)
+	}
+
+	ctx.ModuleForTests("sysprop-platform", "android_common")
+	ctx.ModuleForTests("sysprop-vendor", "android_common")
+
+	// Check for exported includes
+	coreVariant := "android_arm64_armv8-a_core_static"
+	vendorVariant := "android_arm64_armv8-a_vendor_static"
+
+	platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/include"
+	platformSystemCorePath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+	platformSystemVendorPath := "libsysprop-platform/android_arm64_armv8-a_vendor_static/gen/sysprop/system/include"
+
+	platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+
+	vendorInternalPath := "libsysprop-vendor/android_arm64_armv8-a_vendor_static/gen/sysprop/include"
+	vendorSystemPath := "libsysprop-vendor/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+
+	platformClient := ctx.ModuleForTests("cc-client-platform", coreVariant)
+	platformFlags := platformClient.Rule("cc").Args["cFlags"]
+
+	// Platform should use platform's internal header
+	if !strings.Contains(platformFlags, platformInternalPath) {
+		t.Errorf("flags for platform must contain %#v, but was %#v.",
+			platformInternalPath, platformFlags)
+	}
+
+	productClient := ctx.ModuleForTests("cc-client-product", coreVariant)
+	productFlags := productClient.Rule("cc").Args["cFlags"]
+
+	// Product should use platform's and vendor's system headers
+	if !strings.Contains(productFlags, platformOnProductPath) ||
+		!strings.Contains(productFlags, vendorSystemPath) {
+		t.Errorf("flags for product must contain %#v and %#v, but was %#v.",
+			platformSystemCorePath, vendorSystemPath, productFlags)
+	}
+
+	vendorClient := ctx.ModuleForTests("cc-client-vendor", vendorVariant)
+	vendorFlags := vendorClient.Rule("cc").Args["cFlags"]
+
+	// Vendor should use platform's system header and vendor's internal header
+	if !strings.Contains(vendorFlags, platformSystemVendorPath) ||
+		!strings.Contains(vendorFlags, vendorInternalPath) {
+		t.Errorf("flags for vendor must contain %#v and %#v, but was %#v.",
+			platformSystemVendorPath, vendorInternalPath, vendorFlags)
+	}
+}