platform_build_soong/sysprop/sysprop_library.go
mrziwang ba2a460008 Use OutputFilesProvider on syspropJavaGenRule
In the context of incremental soong, the output files
inter-module-communication will be through OutputFilesProvider.
The OutputFileProducer interface will be deprecated.

Test: CI
Bug: 339477385
Change-Id: I3b1cb3a4cfafa1385ef27a427009abb13accf834
2024-06-13 14:16:52 -07:00

705 lines
23 KiB
Go

// 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.
// sysprop package defines a module named sysprop_library that can implement sysprop as API
// See https://source.android.com/devices/architecture/sysprops-apis for details
package sysprop
import (
"fmt"
"io"
"os"
"path"
"strings"
"sync"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/cc"
"android/soong/java"
"android/soong/rust"
)
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
}
type syspropGenProperties struct {
Srcs []string `android:"path"`
Scope string
Name *string
Check_api *string
}
type syspropJavaGenRule struct {
android.ModuleBase
properties syspropGenProperties
}
type syspropRustGenRule struct {
*rust.BaseSourceProvider
properties rustLibraryProperties
}
var _ rust.SourceProvider = (*syspropRustGenRule)(nil)
var (
syspropJava = pctx.AndroidStaticRule("syspropJava",
blueprint.RuleParams{
Command: `rm -rf $out.tmp && mkdir -p $out.tmp && ` +
`$syspropJavaCmd --scope $scope --java-output-dir $out.tmp $in && ` +
`$soongZipCmd -jar -o $out -C $out.tmp -D $out.tmp && rm -rf $out.tmp`,
CommandDeps: []string{
"$syspropJavaCmd",
"$soongZipCmd",
},
}, "scope")
syspropRust = pctx.AndroidStaticRule("syspropRust",
blueprint.RuleParams{
Command: `rm -rf $out_dir && mkdir -p $out_dir && ` +
`$syspropRustCmd --scope $scope --rust-output-dir $out_dir $in`,
CommandDeps: []string{
"$syspropRustCmd",
},
}, "scope", "out_dir")
)
func init() {
pctx.HostBinToolVariable("soongZipCmd", "soong_zip")
pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java")
pctx.HostBinToolVariable("syspropRustCmd", "sysprop_rust")
}
// syspropJavaGenRule module generates srcjar containing generated java APIs.
// It also depends on check api rule, so api check has to pass to use sysprop_library.
func (g *syspropJavaGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var checkApiFileTimeStamp android.WritablePath
ctx.VisitDirectDeps(func(dep android.Module) {
if m, ok := dep.(*syspropLibrary); ok {
checkApiFileTimeStamp = m.checkApiFileTimeStamp
}
})
var genSrcjars android.Paths
for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Srcs) {
srcJarFile := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcjar")
ctx.Build(pctx, android.BuildParams{
Rule: syspropJava,
Description: "sysprop_java " + syspropFile.Rel(),
Output: srcJarFile,
Input: syspropFile,
Implicit: checkApiFileTimeStamp,
Args: map[string]string{
"scope": g.properties.Scope,
},
})
genSrcjars = append(genSrcjars, srcJarFile)
}
ctx.SetOutputFiles(genSrcjars, "")
}
func (g *syspropJavaGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
// Add a dependency from the stubs to sysprop library so that the generator rule can depend on
// the check API rule of the sysprop library.
ctx.AddFarVariationDependencies(nil, nil, proptools.String(g.properties.Check_api))
}
func syspropJavaGenFactory() android.Module {
g := &syspropJavaGenRule{}
g.AddProperties(&g.properties)
android.InitAndroidModule(g)
return g
}
// syspropRustGenRule module generates rust source files containing generated rust APIs.
// It also depends on check api rule, so api check has to pass to use sysprop_library.
func (g *syspropRustGenRule) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path {
var checkApiFileTimeStamp android.WritablePath
ctx.VisitDirectDeps(func(dep android.Module) {
if m, ok := dep.(*syspropLibrary); ok {
checkApiFileTimeStamp = m.checkApiFileTimeStamp
}
})
outputDir := android.PathForModuleOut(ctx, "src")
libFile := outputDir.Join(ctx, "lib.rs")
g.BaseSourceProvider.OutputFiles = append(g.BaseSourceProvider.OutputFiles, libFile)
libFileLines := []string{"//! Autogenerated system property accessors."}
for _, syspropFile := range android.PathsForModuleSrc(ctx, g.properties.Sysprop_srcs) {
moduleName := syspropPathToRustModule(syspropFile)
moduleDir := outputDir.Join(ctx, moduleName)
modulePath := moduleDir.Join(ctx, "mod.rs")
ctx.Build(pctx, android.BuildParams{
Rule: syspropRust,
Description: "sysprop_rust " + syspropFile.Rel(),
Output: modulePath,
Input: syspropFile,
Implicit: checkApiFileTimeStamp,
Args: map[string]string{
"scope": g.properties.Scope,
"out_dir": moduleDir.String(),
},
})
g.BaseSourceProvider.OutputFiles = append(g.BaseSourceProvider.OutputFiles, modulePath)
libFileLines = append(libFileLines, fmt.Sprintf("pub mod %s;", moduleName))
}
libFileSource := strings.Join(libFileLines, "\n")
android.WriteFileRule(ctx, libFile, libFileSource)
return libFile
}
func (g *syspropRustGenRule) SourceProviderProps() []interface{} {
return append(g.BaseSourceProvider.SourceProviderProps(), &g.Properties)
}
// syspropPathToRustModule takes a path to a .sysprop file and returns the name to use for the
// corresponding Rust module.
func syspropPathToRustModule(syspropFilename android.Path) string {
filenameBase := strings.TrimSuffix(syspropFilename.Base(), ".sysprop")
return strings.ToLower(filenameBase)
}
func (g *syspropRustGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
// Add a dependency from the stubs to sysprop library so that the generator rule can depend on
// the check API rule of the sysprop library.
ctx.AddFarVariationDependencies(nil, nil, proptools.String(g.properties.Check_api))
}
func syspropRustGenFactory() android.Module {
g := &syspropRustGenRule{
BaseSourceProvider: rust.NewSourceProvider(),
}
sourceProvider := rust.NewSourceProviderModule(android.DeviceSupported, g, false, false)
sourceProvider.AddProperties(&g.properties)
return sourceProvider.Init()
}
type syspropLibrary struct {
android.ModuleBase
android.ApexModuleBase
properties syspropLibraryProperties
checkApiFileTimeStamp android.WritablePath
latestApiFile android.OptionalPath
currentApiFile android.OptionalPath
dumpedApiFile android.WritablePath
}
type syspropLibraryProperties struct {
// Determine who owns this sysprop library. Possible values are
// "Platform", "Vendor", or "Odm"
Property_owner string
// list of package names that will be documented and publicized as API
Api_packages []string
// If set to true, allow this module to be dexed and installed on devices.
Installable *bool
// Make this module available when building for ramdisk
Ramdisk_available *bool
// Make this module available when building for recovery
Recovery_available *bool
// Make this module available when building for vendor
Vendor_available *bool
// Make this module available when building for product
Product_available *bool
// list of .sysprop files which defines the properties.
Srcs []string `android:"path"`
// If set to true, build a variant of the module for the host. Defaults to false.
Host_supported *bool
Cpp struct {
// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
// Forwarded to cc_library.min_sdk_version
Min_sdk_version *string
// C compiler flags used to build library
Cflags []string
// Linker flags used to build binary
Ldflags []string
}
Java struct {
// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
// Forwarded to java_library.min_sdk_version
Min_sdk_version *string
}
Rust struct {
// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
// Forwarded to rust_library.min_sdk_version
Min_sdk_version *string
}
}
var (
pctx = android.NewPackageContext("android/soong/sysprop")
syspropCcTag = dependencyTag{name: "syspropCc"}
syspropLibrariesKey = android.NewOnceKey("syspropLibraries")
syspropLibrariesLock sync.Mutex
)
// List of sysprop_library used by property_contexts to perform type check.
func syspropLibraries(config android.Config) *[]string {
return config.Once(syspropLibrariesKey, func() interface{} {
return &[]string{}
}).(*[]string)
}
func SyspropLibraries(config android.Config) []string {
return append([]string{}, *syspropLibraries(config)...)
}
func init() {
registerSyspropBuildComponents(android.InitRegistrationContext)
}
func registerSyspropBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("sysprop_library", syspropLibraryFactory)
}
func (m *syspropLibrary) Name() string {
return m.BaseModuleName() + "_sysprop_library"
}
func (m *syspropLibrary) Owner() string {
return m.properties.Property_owner
}
func (m *syspropLibrary) CcImplementationModuleName() string {
return "lib" + m.BaseModuleName()
}
func (m *syspropLibrary) javaPublicStubName() string {
return m.BaseModuleName() + "_public"
}
func (m *syspropLibrary) javaGenModuleName() string {
return m.BaseModuleName() + "_java_gen"
}
func (m *syspropLibrary) javaGenPublicStubName() string {
return m.BaseModuleName() + "_java_gen_public"
}
func (m *syspropLibrary) rustGenStubName() string {
return "lib" + m.rustCrateName() + "_rust"
}
func (m *syspropLibrary) rustCrateName() string {
moduleName := strings.ToLower(m.BaseModuleName())
moduleName = strings.ReplaceAll(moduleName, "-", "_")
moduleName = strings.ReplaceAll(moduleName, ".", "_")
return moduleName
}
func (m *syspropLibrary) BaseModuleName() string {
return m.ModuleBase.Name()
}
func (m *syspropLibrary) CurrentSyspropApiFile() android.OptionalPath {
return m.currentApiFile
}
// GenerateAndroidBuildActions of sysprop_library handles API dump and API check.
// generated java_library will depend on these API files.
func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
baseModuleName := m.BaseModuleName()
srcs := android.PathsForModuleSrc(ctx, m.properties.Srcs)
for _, syspropFile := range srcs {
if syspropFile.Ext() != ".sysprop" {
ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String())
}
}
android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()})
if ctx.Failed() {
return
}
apiDirectoryPath := path.Join(ctx.ModuleDir(), "api")
currentApiFilePath := path.Join(apiDirectoryPath, baseModuleName+"-current.txt")
latestApiFilePath := path.Join(apiDirectoryPath, baseModuleName+"-latest.txt")
m.currentApiFile = android.ExistentPathForSource(ctx, currentApiFilePath)
m.latestApiFile = android.ExistentPathForSource(ctx, latestApiFilePath)
// dump API rule
rule := android.NewRuleBuilder(pctx, ctx)
m.dumpedApiFile = android.PathForModuleOut(ctx, "api-dump.txt")
rule.Command().
BuiltTool("sysprop_api_dump").
Output(m.dumpedApiFile).
Inputs(srcs)
rule.Build(baseModuleName+"_api_dump", baseModuleName+" api dump")
// check API rule
rule = android.NewRuleBuilder(pctx, ctx)
// We allow that the API txt files don't exist, when the sysprop_library only contains internal
// properties. But we have to feed current api file and latest api file to the rule builder.
// Currently we can't get android.Path representing the null device, so we add any existing API
// txt files to implicits, and then directly feed string paths, rather than calling Input(Path)
// method.
var apiFileList android.Paths
currentApiArgument := os.DevNull
if m.currentApiFile.Valid() {
apiFileList = append(apiFileList, m.currentApiFile.Path())
currentApiArgument = m.currentApiFile.String()
}
latestApiArgument := os.DevNull
if m.latestApiFile.Valid() {
apiFileList = append(apiFileList, m.latestApiFile.Path())
latestApiArgument = m.latestApiFile.String()
}
// 1. compares current.txt to api-dump.txt
// current.txt should be identical to api-dump.txt.
msg := fmt.Sprintf(`\n******************************\n`+
`API of sysprop_library %s doesn't match with current.txt\n`+
`Please update current.txt by:\n`+
`m %s-dump-api && mkdir -p %q && rm -rf %q && cp -f %q %q\n`+
`******************************\n`, baseModuleName, baseModuleName,
apiDirectoryPath, currentApiFilePath, m.dumpedApiFile.String(), currentApiFilePath)
rule.Command().
Text("( cmp").Flag("-s").
Input(m.dumpedApiFile).
Text(currentApiArgument).
Text("|| ( echo").Flag("-e").
Flag(`"` + msg + `"`).
Text("; exit 38) )")
// 2. compares current.txt to latest.txt (frozen API)
// current.txt should be compatible with latest.txt
msg = fmt.Sprintf(`\n******************************\n`+
`API of sysprop_library %s doesn't match with latest version\n`+
`Please fix the breakage and rebuild.\n`+
`******************************\n`, baseModuleName)
rule.Command().
Text("( ").
BuiltTool("sysprop_api_checker").
Text(latestApiArgument).
Text(currentApiArgument).
Text(" || ( echo").Flag("-e").
Flag(`"` + msg + `"`).
Text("; exit 38) )").
Implicits(apiFileList)
m.checkApiFileTimeStamp = android.PathForModuleOut(ctx, "check_api.timestamp")
rule.Command().
Text("touch").
Output(m.checkApiFileTimeStamp)
rule.Build(baseModuleName+"_check_api", baseModuleName+" check api")
}
func (m *syspropLibrary) AndroidMk() android.AndroidMkData {
return android.AndroidMkData{
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
// sysprop_library module itself is defined as a FAKE module to perform API check.
// Actual implementation libraries are created on LoadHookMutator
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)", " # sysprop.syspropLibrary")
fmt.Fprintln(w, "LOCAL_MODULE :=", m.Name())
fmt.Fprintf(w, "LOCAL_MODULE_CLASS := FAKE\n")
fmt.Fprintf(w, "LOCAL_MODULE_TAGS := optional\n")
// AconfigUpdateAndroidMkData may have added elements to Extra. Process them here.
for _, extra := range data.Extra {
extra(w, nil)
}
fmt.Fprintf(w, "include $(BUILD_SYSTEM)/base_rules.mk\n\n")
fmt.Fprintf(w, "$(LOCAL_BUILT_MODULE): %s\n", m.checkApiFileTimeStamp.String())
fmt.Fprintf(w, "\ttouch $@\n\n")
fmt.Fprintf(w, ".PHONY: %s-check-api %s-dump-api\n\n", name, name)
// dump API rule
fmt.Fprintf(w, "%s-dump-api: %s\n\n", name, m.dumpedApiFile.String())
// check API rule
fmt.Fprintf(w, "%s-check-api: %s\n\n", name, m.checkApiFileTimeStamp.String())
}}
}
var _ android.ApexModule = (*syspropLibrary)(nil)
// Implements android.ApexModule
func (m *syspropLibrary) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
sdkVersion android.ApiLevel) error {
return fmt.Errorf("sysprop_library is not supposed to be part of apex modules")
}
// sysprop_library creates schematized APIs from sysprop description files (.sysprop).
// Both Java and C++ modules can link against sysprop_library, and API stability check
// against latest APIs (see build/soong/scripts/freeze-sysprop-api-files.sh)
// is performed. Note that the generated C++ module has its name prefixed with
// `lib`, and it is this module that should be depended on from other C++
// modules; i.e., if the sysprop_library module is named `foo`, C++ modules
// should depend on `libfoo`.
func syspropLibraryFactory() android.Module {
m := &syspropLibrary{}
m.AddProperties(
&m.properties,
)
android.InitAndroidModule(m)
android.InitApexModule(m)
android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
return m
}
type ccLibraryProperties struct {
Name *string
Srcs []string
Soc_specific *bool
Device_specific *bool
Product_specific *bool
Sysprop struct {
Platform *bool
}
Target struct {
Android struct {
Header_libs []string
Shared_libs []string
}
Host struct {
Static_libs []string
}
}
Required []string
Recovery *bool
Recovery_available *bool
Vendor_available *bool
Product_available *bool
Ramdisk_available *bool
Host_supported *bool
Apex_available []string
Min_sdk_version *string
Cflags []string
Ldflags []string
}
type javaLibraryProperties struct {
Name *string
Srcs []string
Soc_specific *bool
Device_specific *bool
Product_specific *bool
Required []string
Sdk_version *string
Installable *bool
Libs []string
Stem *string
SyspropPublicStub string
Apex_available []string
Min_sdk_version *string
}
type rustLibraryProperties struct {
Name *string
Sysprop_srcs []string `android:"path"`
Scope string
Check_api *string
Srcs []string
Installable *bool
Crate_name string
Rustlibs []string
Vendor_available *bool
Product_available *bool
Apex_available []string
Min_sdk_version *string
}
func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
if len(m.properties.Srcs) == 0 {
ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs")
}
// ctx's Platform or Specific functions represent where this sysprop_library installed.
installedInSystem := ctx.Platform() || ctx.SystemExtSpecific()
installedInVendorOrOdm := ctx.SocSpecific() || ctx.DeviceSpecific()
installedInProduct := ctx.ProductSpecific()
isOwnerPlatform := false
var javaSyspropStub string
// javaSyspropStub contains stub libraries used by generated APIs, instead of framework stub.
// This is to make sysprop_library link against core_current.
if installedInVendorOrOdm {
javaSyspropStub = "sysprop-library-stub-vendor"
} else if installedInProduct {
javaSyspropStub = "sysprop-library-stub-product"
} else {
javaSyspropStub = "sysprop-library-stub-platform"
}
switch m.Owner() {
case "Platform":
// Every partition can access platform-defined properties
isOwnerPlatform = true
case "Vendor":
// System can't access vendor's properties
if installedInSystem {
ctx.ModuleErrorf("None of soc_specific, device_specific, product_specific is true. " +
"System can't access sysprop_library owned by Vendor")
}
case "Odm":
// Only vendor can access Odm-defined properties
if !installedInVendorOrOdm {
ctx.ModuleErrorf("Neither soc_speicifc nor device_specific is true. " +
"Odm-defined properties should be accessed only in Vendor or Odm")
}
default:
ctx.PropertyErrorf("property_owner",
"Unknown value %s: must be one of Platform, Vendor or Odm", m.Owner())
}
// Generate a C++ implementation library.
// cc_library can receive *.sysprop files as their srcs, generating sources itself.
ccProps := ccLibraryProperties{}
ccProps.Name = proptools.StringPtr(m.CcImplementationModuleName())
ccProps.Srcs = m.properties.Srcs
ccProps.Soc_specific = proptools.BoolPtr(ctx.SocSpecific())
ccProps.Device_specific = proptools.BoolPtr(ctx.DeviceSpecific())
ccProps.Product_specific = proptools.BoolPtr(ctx.ProductSpecific())
ccProps.Sysprop.Platform = proptools.BoolPtr(isOwnerPlatform)
ccProps.Target.Android.Header_libs = []string{"libbase_headers"}
ccProps.Target.Android.Shared_libs = []string{"liblog"}
ccProps.Target.Host.Static_libs = []string{"libbase", "liblog"}
ccProps.Recovery_available = m.properties.Recovery_available
ccProps.Vendor_available = m.properties.Vendor_available
ccProps.Product_available = m.properties.Product_available
ccProps.Ramdisk_available = m.properties.Ramdisk_available
ccProps.Host_supported = m.properties.Host_supported
ccProps.Apex_available = m.ApexProperties.Apex_available
ccProps.Min_sdk_version = m.properties.Cpp.Min_sdk_version
ccProps.Cflags = m.properties.Cpp.Cflags
ccProps.Ldflags = m.properties.Cpp.Ldflags
ctx.CreateModule(cc.LibraryFactory, &ccProps)
scope := "internal"
// We need to only use public version, if the partition where sysprop_library will be installed
// is different from owner.
if ctx.ProductSpecific() {
// Currently product partition can't own any sysprop_library. So product always uses public.
scope = "public"
} else if isOwnerPlatform && installedInVendorOrOdm {
// Vendor or Odm should use public version of Platform's sysprop_library.
scope = "public"
}
// Generate a Java implementation library.
// Contrast to C++, syspropJavaGenRule module will generate srcjar and the srcjar will be fed
// to Java implementation library.
ctx.CreateModule(syspropJavaGenFactory, &syspropGenProperties{
Srcs: m.properties.Srcs,
Scope: scope,
Name: proptools.StringPtr(m.javaGenModuleName()),
Check_api: proptools.StringPtr(ctx.ModuleName()),
})
// if platform sysprop_library is installed in /system or /system-ext, we regard it as an API
// and allow any modules (even from different partition) to link against the sysprop_library.
// To do that, we create a public stub and expose it to modules with sdk_version: system_*.
var publicStub string
if isOwnerPlatform && installedInSystem {
publicStub = m.javaPublicStubName()
}
ctx.CreateModule(java.LibraryFactory, &javaLibraryProperties{
Name: proptools.StringPtr(m.BaseModuleName()),
Srcs: []string{":" + m.javaGenModuleName()},
Soc_specific: proptools.BoolPtr(ctx.SocSpecific()),
Device_specific: proptools.BoolPtr(ctx.DeviceSpecific()),
Product_specific: proptools.BoolPtr(ctx.ProductSpecific()),
Installable: m.properties.Installable,
Sdk_version: proptools.StringPtr("core_current"),
Libs: []string{javaSyspropStub},
SyspropPublicStub: publicStub,
Apex_available: m.ApexProperties.Apex_available,
Min_sdk_version: m.properties.Java.Min_sdk_version,
})
if publicStub != "" {
ctx.CreateModule(syspropJavaGenFactory, &syspropGenProperties{
Srcs: m.properties.Srcs,
Scope: "public",
Name: proptools.StringPtr(m.javaGenPublicStubName()),
Check_api: proptools.StringPtr(ctx.ModuleName()),
})
ctx.CreateModule(java.LibraryFactory, &javaLibraryProperties{
Name: proptools.StringPtr(publicStub),
Srcs: []string{":" + m.javaGenPublicStubName()},
Installable: proptools.BoolPtr(false),
Sdk_version: proptools.StringPtr("core_current"),
Libs: []string{javaSyspropStub},
Stem: proptools.StringPtr(m.BaseModuleName()),
})
}
// Generate a Rust implementation library.
rustProps := rustLibraryProperties{
Name: proptools.StringPtr(m.rustGenStubName()),
Sysprop_srcs: m.properties.Srcs,
Scope: scope,
Check_api: proptools.StringPtr(ctx.ModuleName()),
Installable: proptools.BoolPtr(false),
Crate_name: m.rustCrateName(),
Rustlibs: []string{
"liblog_rust",
"librustutils",
},
Vendor_available: m.properties.Vendor_available,
Product_available: m.properties.Product_available,
Apex_available: m.ApexProperties.Apex_available,
Min_sdk_version: proptools.StringPtr("29"),
}
ctx.CreateModule(syspropRustGenFactory, &rustProps)
// syspropLibraries will be used by property_contexts to check types.
// Record absolute paths of sysprop_library to prevent soong_namespace problem.
if m.ExportedToMake() {
syspropLibrariesLock.Lock()
defer syspropLibrariesLock.Unlock()
libraries := syspropLibraries(ctx.Config())
*libraries = append(*libraries, "//"+ctx.ModuleDir()+":"+ctx.ModuleName())
}
}