123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586 |
- // 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"
- "sync"
- "android/soong/bazel"
- "github.com/google/blueprint"
- "github.com/google/blueprint/proptools"
- "android/soong/android"
- "android/soong/cc"
- "android/soong/java"
- )
- 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
- genSrcjars android.Paths
- }
- var _ android.OutputFileProducer = (*syspropJavaGenRule)(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")
- )
- func init() {
- pctx.HostBinToolVariable("soongZipCmd", "soong_zip")
- pctx.HostBinToolVariable("syspropJavaCmd", "sysprop_java")
- }
- // 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
- }
- })
- 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,
- },
- })
- g.genSrcjars = append(g.genSrcjars, srcJarFile)
- }
- }
- 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 (g *syspropJavaGenRule) OutputFiles(tag string) (android.Paths, error) {
- switch tag {
- case "":
- return g.genSrcjars, nil
- default:
- return nil, fmt.Errorf("unsupported module reference tag %q", tag)
- }
- }
- func syspropJavaGenFactory() android.Module {
- g := &syspropJavaGenRule{}
- g.AddProperties(&g.properties)
- android.InitAndroidModule(g)
- return g
- }
- type syspropLibrary struct {
- android.ModuleBase
- android.ApexModuleBase
- android.BazelModuleBase
- 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
- }
- 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
- }
- }
- 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) 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()
- for _, syspropFile := range android.PathsForModuleSrc(ctx, m.properties.Srcs) {
- if syspropFile.Ext() != ".sysprop" {
- ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String())
- }
- }
- 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(android.PathsForModuleSrc(ctx, m.properties.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())
- data.Entries.WriteLicenseVariables(w)
- fmt.Fprintf(w, "LOCAL_MODULE_CLASS := FAKE\n")
- fmt.Fprintf(w, "LOCAL_MODULE_TAGS := optional\n")
- 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.InitBazelModule(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
- Bazel_module struct {
- Bp2build_available *bool
- }
- }
- 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
- }
- 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
- // A Bazel macro handles this, so this module does not need to be handled
- // in bp2build
- // TODO(b/237810289) perhaps do something different here so that we aren't
- // also disabling these modules in mixed builds
- ccProps.Bazel_module.Bp2build_available = proptools.BoolPtr(false)
- 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()),
- })
- }
- // 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())
- }
- }
- // TODO(b/240463568): Additional properties will be added for API validation
- func (m *syspropLibrary) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
- labels := cc.SyspropLibraryLabels{
- SyspropLibraryLabel: m.BaseModuleName(),
- SharedLibraryLabel: m.CcImplementationModuleName(),
- StaticLibraryLabel: cc.BazelLabelNameForStaticModule(m.CcImplementationModuleName()),
- }
- cc.Bp2buildSysprop(ctx,
- labels,
- bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)),
- m.properties.Cpp.Min_sdk_version)
- }
|