diff --git a/Android.bp b/Android.bp index d469f41a1..75761027d 100644 --- a/Android.bp +++ b/Android.bp @@ -298,6 +298,7 @@ bootstrap_go_package { "java/sdk.go", "java/sdk_library.go", "java/support_libraries.go", + "java/sysprop.go", "java/system_modules.go", "java/testing.go", "java/tradefed.go", diff --git a/cc/cc.go b/cc/cc.go index 949e671e6..4c9d42b0b 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -42,7 +42,7 @@ func init() { ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel() ctx.BottomUp("version", VersionMutator).Parallel() ctx.BottomUp("begin", BeginMutator).Parallel() - ctx.BottomUp("sysprop", SyspropMutator).Parallel() + ctx.BottomUp("sysprop_cc", SyspropMutator).Parallel() }) android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) { diff --git a/java/java.go b/java/java.go index 9745da45e..052e06f6f 100644 --- a/java/java.go +++ b/java/java.go @@ -594,8 +594,36 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { } } - ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) - ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs...) + syspropPublicStubs := syspropPublicStubs(ctx.Config()) + + // rewriteSyspropLibs validates if a java module can link against platform's sysprop_library, + // and redirects dependency to public stub depending on the link type. + rewriteSyspropLibs := func(libs []string, prop string) []string { + // make a copy + ret := android.CopyOf(libs) + + for idx, lib := range libs { + stub, ok := syspropPublicStubs[lib] + + if !ok { + continue + } + + linkType, _ := j.getLinkType(ctx.ModuleName()) + if linkType == javaSystem { + ret[idx] = stub + } else if linkType != javaPlatform { + ctx.PropertyErrorf("sdk_version", + "can't link against sysprop_library %q from a module using public or core API", + lib) + } + } + + return ret + } + + ctx.AddVariationDependencies(nil, libTag, rewriteSyspropLibs(j.properties.Libs, "libs")...) + ctx.AddVariationDependencies(nil, staticLibTag, rewriteSyspropLibs(j.properties.Static_libs, "static_libs")...) ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...) ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), exportedPluginTag, j.properties.Exported_plugins...) diff --git a/java/sysprop.go b/java/sysprop.go new file mode 100644 index 000000000..1a70499b8 --- /dev/null +++ b/java/sysprop.go @@ -0,0 +1,60 @@ +// 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 java + +import ( + "sync" + + "android/soong/android" +) + +type syspropLibraryInterface interface { + BaseModuleName() string + Owner() string + HasPublicStub() bool + JavaPublicStubName() string +} + +var ( + syspropPublicStubsKey = android.NewOnceKey("syspropPublicStubsJava") + syspropPublicStubsLock sync.Mutex +) + +func init() { + android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("sysprop_java", SyspropMutator).Parallel() + }) +} + +func syspropPublicStubs(config android.Config) map[string]string { + return config.Once(syspropPublicStubsKey, func() interface{} { + return make(map[string]string) + }).(map[string]string) +} + +// gather list of sysprop libraries owned by platform. +func SyspropMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(syspropLibraryInterface); ok { + if m.Owner() != "Platform" || !m.HasPublicStub() { + return + } + + syspropPublicStubs := syspropPublicStubs(mctx.Config()) + syspropPublicStubsLock.Lock() + defer syspropPublicStubsLock.Unlock() + + syspropPublicStubs[m.BaseModuleName()] = m.JavaPublicStubName() + } +} diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index 1fc94dbea..ce404f8a7 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -35,6 +35,7 @@ type dependencyTag struct { type syspropGenProperties struct { Srcs []string `android:"path"` Scope string + Name *string } type syspropJavaGenRule struct { @@ -142,6 +143,9 @@ type syspropLibraryProperties struct { // list of .sysprop files which defines the properties. Srcs []string `android:"path"` + + // Whether public stub exists or not. + Public_stub *bool `blueprint:"mutated"` } var ( @@ -157,18 +161,37 @@ func (m *syspropLibrary) Name() string { return m.BaseModuleName() + "_sysprop_library" } +func (m *syspropLibrary) Owner() string { + return m.properties.Property_owner +} + func (m *syspropLibrary) CcModuleName() string { return "lib" + m.BaseModuleName() } +func (m *syspropLibrary) JavaPublicStubName() string { + if proptools.Bool(m.properties.Public_stub) { + return m.BaseModuleName() + "_public" + } + return "" +} + 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) HasPublicStub() bool { + return proptools.Bool(m.properties.Public_stub) +} + func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { baseModuleName := m.BaseModuleName() @@ -274,6 +297,36 @@ func syspropLibraryFactory() android.Module { return m } +type ccLibraryProperties 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 +} + +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 +} + func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { if len(m.properties.Srcs) == 0 { ctx.PropertyErrorf("srcs", "sysprop_library must specify srcs") @@ -304,120 +357,107 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { return } - socSpecific := ctx.SocSpecific() - deviceSpecific := ctx.DeviceSpecific() - productSpecific := ctx.ProductSpecific() - - owner := m.properties.Property_owner + // ctx's Platform or Specific functions represent where this sysprop_library installed. + installedInSystem := ctx.Platform() || ctx.SystemExtSpecific() + installedInVendorOrOdm := ctx.SocSpecific() || ctx.DeviceSpecific() + isOwnerPlatform := false stub := "sysprop-library-stub-" - switch owner { + switch m.Owner() { case "Platform": // Every partition can access platform-defined properties stub += "platform" + isOwnerPlatform = true case "Vendor": // System can't access vendor's properties - if !socSpecific && !deviceSpecific && !productSpecific { + if installedInSystem { 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 { + if !installedInVendorOrOdm { 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) + "Unknown value %s: must be one of Platform, Vendor or Odm", m.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 := ccLibraryProperties{} 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.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.Header_libs = []string{"libbase_headers"} ccProps.Shared_libs = []string{"liblog"} ccProps.Recovery_available = m.properties.Recovery_available ccProps.Vendor_available = m.properties.Vendor_available - ctx.CreateModule(cc.LibraryFactory, &ccProps) - // internal scope contains all properties - // public scope only contains public properties - // use public if the owner is different from client scope := "internal" - isProduct := ctx.ProductSpecific() - isVendor := ctx.SocSpecific() - isOwnerPlatform := owner == "Platform" - if isProduct { - // product can't own any sysprop_library now, so product must use public scope + // 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. scope = "public" - } else if isVendor && isOwnerPlatform { - // vendor and odm can only use the public properties from the platform + } else if isOwnerPlatform && installedInVendorOrOdm { + // Vendor or Odm should use public version of Platform's sysprop_library. scope = "public" } - javaGenProps := struct { - Srcs []string - Scope string - Name *string - }{ + ctx.CreateModule(syspropJavaGenFactory, &syspropGenProperties{ Srcs: m.properties.Srcs, Scope: scope, Name: proptools.StringPtr(m.javaGenModuleName()), + }) + + 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{stub}, + }) + + // 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_*. + if isOwnerPlatform && installedInSystem { + m.properties.Public_stub = proptools.BoolPtr(true) + ctx.CreateModule(syspropJavaGenFactory, &syspropGenProperties{ + Srcs: m.properties.Srcs, + Scope: "public", + Name: proptools.StringPtr(m.javaGenPublicStubName()), + }) + + ctx.CreateModule(java.LibraryFactory, &javaLibraryProperties{ + Name: proptools.StringPtr(m.JavaPublicStubName()), + Srcs: []string{":" + m.javaGenPublicStubName()}, + Installable: proptools.BoolPtr(false), + Sdk_version: proptools.StringPtr("core_current"), + Libs: []string{stub}, + Stem: proptools.StringPtr(m.BaseModuleName()), + }) } - - ctx.CreateModule(syspropJavaGenFactory, &javaGenProps) - - javaProps := struct { - Name *string - Srcs []string - Soc_specific *bool - Device_specific *bool - Product_specific *bool - Required []string - Sdk_version *string - Installable *bool - Libs []string - }{} - - javaProps.Name = proptools.StringPtr(m.BaseModuleName()) - javaProps.Srcs = []string{":" + *javaGenProps.Name} - javaProps.Soc_specific = proptools.BoolPtr(socSpecific) - javaProps.Device_specific = proptools.BoolPtr(deviceSpecific) - javaProps.Product_specific = proptools.BoolPtr(productSpecific) - javaProps.Installable = m.properties.Installable - javaProps.Sdk_version = proptools.StringPtr("core_current") - javaProps.Libs = []string{stub} - - ctx.CreateModule(java.LibraryFactory, &javaProps) } func syspropDepsMutator(ctx android.BottomUpMutatorContext) { if m, ok := ctx.Module().(*syspropLibrary); ok { ctx.AddReverseDependency(m, nil, m.javaGenModuleName()) + + if proptools.Bool(m.properties.Public_stub) { + ctx.AddReverseDependency(m, nil, m.javaGenPublicStubName()) + } } } diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go index 9d4c1aa83..6ac3f4c96 100644 --- a/sysprop/sysprop_test.go +++ b/sysprop/sysprop_test.go @@ -24,6 +24,7 @@ import ( "strings" "testing" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -76,7 +77,8 @@ func testContext(config android.Config) *android.TestContext { 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.BottomUp("sysprop_cc", cc.SyspropMutator).Parallel() + ctx.BottomUp("sysprop_java", java.SyspropMutator).Parallel() }) ctx.RegisterModuleType("sysprop_library", syspropLibraryFactory) @@ -204,6 +206,13 @@ func TestSyspropLibrary(t *testing.T) { libs: ["sysprop-platform"], } + java_library { + name: "java-platform-private", + srcs: ["c.java"], + platform_apis: true, + libs: ["sysprop-platform"], + } + java_library { name: "java-product", srcs: ["c.java"], @@ -302,6 +311,7 @@ func TestSyspropLibrary(t *testing.T) { } ctx.ModuleForTests("sysprop-platform", "android_common") + ctx.ModuleForTests("sysprop-platform_public", "android_common") ctx.ModuleForTests("sysprop-vendor", "android_common") // Check for exported includes @@ -354,4 +364,17 @@ func TestSyspropLibrary(t *testing.T) { t.Errorf("flags for vendor must contain %#v and %#v, but was %#v.", platformPublicVendorPath, vendorInternalPath, vendorFlags) } + + // Java modules linking against system API should use public stub + javaSystemApiClient := ctx.ModuleForTests("java-platform", "android_common") + publicStubFound := false + ctx.VisitDirectDeps(javaSystemApiClient.Module(), func(dep blueprint.Module) { + if dep.Name() == "sysprop-platform_public" { + publicStubFound = true + } + }) + if !publicStubFound { + t.Errorf("system api client should use public stub") + } + }