| // 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 ( |
| "fmt" |
| "io" |
| "path" |
| |
| "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 syspropLibrary struct { |
| android.ModuleBase |
| |
| properties syspropLibraryProperties |
| |
| checkApiFileTimeStamp android.WritablePath |
| latestApiFile android.Path |
| currentApiFile android.Path |
| 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 recovery |
| Recovery_available *bool |
| |
| // Make this module available when building for vendor |
| Vendor_available *bool |
| |
| // list of .sysprop files which defines the properties. |
| Srcs []string `android:"path"` |
| } |
| |
| var ( |
| pctx = android.NewPackageContext("android/soong/sysprop") |
| syspropCcTag = dependencyTag{name: "syspropCc"} |
| ) |
| |
| func init() { |
| android.RegisterModuleType("sysprop_library", syspropLibraryFactory) |
| } |
| |
| func (m *syspropLibrary) Name() string { |
| return m.BaseModuleName() + "_sysprop_library" |
| } |
| |
| func (m *syspropLibrary) CcModuleName() string { |
| return "lib" + m.BaseModuleName() |
| } |
| |
| func (m *syspropLibrary) BaseModuleName() string { |
| return m.ModuleBase.Name() |
| } |
| |
| func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { |
| m.currentApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-current.txt") |
| m.latestApiFile = android.PathForSource(ctx, ctx.ModuleDir(), "api", m.BaseModuleName()+"-latest.txt") |
| |
| // dump API rule |
| rule := android.NewRuleBuilder() |
| m.dumpedApiFile = android.PathForModuleOut(ctx, "api-dump.txt") |
| rule.Command(). |
| BuiltTool(ctx, "sysprop_api_dump"). |
| Output(m.dumpedApiFile). |
| Inputs(android.PathsForModuleSrc(ctx, m.properties.Srcs)) |
| rule.Build(pctx, ctx, m.BaseModuleName()+"_api_dump", m.BaseModuleName()+" api dump") |
| |
| // check API rule |
| rule = android.NewRuleBuilder() |
| |
| // 1. current.txt <-> 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`+ |
| `rm -rf %q && cp -f %q %q\n`+ |
| `******************************\n`, m.BaseModuleName(), |
| m.currentApiFile.String(), m.dumpedApiFile.String(), m.currentApiFile.String()) |
| |
| rule.Command(). |
| Text("( cmp").Flag("-s"). |
| Input(m.dumpedApiFile). |
| Input(m.currentApiFile). |
| Text("|| ( echo").Flag("-e"). |
| Flag(`"` + msg + `"`). |
| Text("; exit 38) )") |
| |
| // 2. current.txt <-> 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`, m.BaseModuleName()) |
| |
| rule.Command(). |
| Text("( "). |
| BuiltTool(ctx, "sysprop_api_checker"). |
| Input(m.latestApiFile). |
| Input(m.currentApiFile). |
| Text(" || ( echo").Flag("-e"). |
| Flag(`"` + msg + `"`). |
| Text("; exit 38) )") |
| |
| m.checkApiFileTimeStamp = android.PathForModuleOut(ctx, "check_api.timestamp") |
| |
| rule.Command(). |
| Text("touch"). |
| Output(m.checkApiFileTimeStamp) |
| |
| rule.Build(pctx, ctx, m.BaseModuleName()+"_check_api", m.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)") |
| fmt.Fprintf(w, "LOCAL_MODULE := %s\n", m.Name()) |
| 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\n\n", name) |
| |
| // check API rule |
| fmt.Fprintf(w, "%s-check-api: %s\n\n", name, m.checkApiFileTimeStamp.String()) |
| |
| // "make {sysprop_library}" should also build the C++ library |
| fmt.Fprintf(w, "%s: %s\n\n", name, m.CcModuleName()) |
| }} |
| } |
| |
| // 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. |
| func syspropLibraryFactory() android.Module { |
| m := &syspropLibrary{} |
| |
| m.AddProperties( |
| &m.properties, |
| ) |
| android.InitAndroidModule(m) |
| android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) }) |
| return m |
| } |
| |
| func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { |
| if len(m.properties.Srcs) == 0 { |
| ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs") |
| } |
| |
| missing_api := false |
| |
| for _, txt := range []string{"-current.txt", "-latest.txt"} { |
| path := path.Join(ctx.ModuleDir(), "api", m.BaseModuleName()+txt) |
| file := android.ExistentPathForSource(ctx, path) |
| if !file.Valid() { |
| ctx.ModuleErrorf("API file %#v doesn't exist", path) |
| missing_api = true |
| } |
| } |
| |
| if missing_api { |
| script := "build/soong/scripts/gen-sysprop-api-files.sh" |
| p := android.ExistentPathForSource(ctx, script) |
| |
| if !p.Valid() { |
| panic(fmt.Sprintf("script file %s doesn't exist", script)) |
| } |
| |
| ctx.ModuleErrorf("One or more api files are missing. "+ |
| "You can create them by:\n"+ |
| "%s %q %q", script, ctx.ModuleDir(), m.BaseModuleName()) |
| return |
| } |
| |
| socSpecific := ctx.SocSpecific() |
| deviceSpecific := ctx.DeviceSpecific() |
| productSpecific := ctx.ProductSpecific() |
| |
| owner := m.properties.Property_owner |
| stub := "sysprop-library-stub-" |
| |
| switch owner { |
| case "Platform": |
| // Every partition can access platform-defined properties |
| stub += "platform" |
| case "Vendor": |
| // System can't access vendor's properties |
| if !socSpecific && !deviceSpecific && !productSpecific { |
| ctx.ModuleErrorf("None of soc_specific, device_specific, product_specific is true. " + |
| "System can't access sysprop_library owned by Vendor") |
| } |
| stub += "vendor" |
| case "Odm": |
| // Only vendor can access Odm-defined properties |
| if !socSpecific && !deviceSpecific { |
| ctx.ModuleErrorf("Neither soc_speicifc nor device_specific is true. " + |
| "Odm-defined properties should be accessed only in Vendor or Odm") |
| } |
| stub += "vendor" |
| default: |
| ctx.PropertyErrorf("property_owner", |
| "Unknown value %s: must be one of Platform, Vendor or Odm", owner) |
| } |
| |
| ccProps := struct { |
| Name *string |
| Srcs []string |
| Soc_specific *bool |
| Device_specific *bool |
| Product_specific *bool |
| Sysprop struct { |
| Platform *bool |
| } |
| Header_libs []string |
| Shared_libs []string |
| Required []string |
| Recovery *bool |
| Recovery_available *bool |
| Vendor_available *bool |
| }{} |
| |
| ccProps.Name = proptools.StringPtr(m.CcModuleName()) |
| ccProps.Srcs = m.properties.Srcs |
| ccProps.Soc_specific = proptools.BoolPtr(socSpecific) |
| ccProps.Device_specific = proptools.BoolPtr(deviceSpecific) |
| ccProps.Product_specific = proptools.BoolPtr(productSpecific) |
| ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform") |
| ccProps.Header_libs = []string{"libbase_headers"} |
| ccProps.Shared_libs = []string{"liblog"} |
| |
| // add sysprop_library module to perform check API |
| ccProps.Required = []string{m.Name()} |
| ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform") |
| ccProps.Recovery_available = m.properties.Recovery_available |
| ccProps.Vendor_available = m.properties.Vendor_available |
| |
| ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProps) |
| |
| javaProps := struct { |
| Name *string |
| Srcs []string |
| Soc_specific *bool |
| Device_specific *bool |
| Product_specific *bool |
| Sysprop struct { |
| Platform *bool |
| } |
| Required []string |
| Sdk_version *string |
| Installable *bool |
| Libs []string |
| }{} |
| |
| javaProps.Name = proptools.StringPtr(m.BaseModuleName()) |
| javaProps.Srcs = m.properties.Srcs |
| javaProps.Soc_specific = proptools.BoolPtr(socSpecific) |
| javaProps.Device_specific = proptools.BoolPtr(deviceSpecific) |
| javaProps.Product_specific = proptools.BoolPtr(productSpecific) |
| javaProps.Installable = m.properties.Installable |
| |
| // add sysprop_library module to perform check API |
| javaProps.Required = []string{m.Name()} |
| javaProps.Sdk_version = proptools.StringPtr("core_current") |
| javaProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform") |
| javaProps.Libs = []string{stub} |
| |
| ctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProps) |
| } |