Add sdk mutator for native modules

Compiling native modules against the NDK disables platform features
like ASAN.  For anything shipped on the system image there is no
reason to compile against the NDK.  Add a new mutator to Soong that
creates a platform and an SDK variant for modules that set
sdk_version, and ignore sdk_version for the platform variant.  The
SDK variant will be used for embedding in APKs that may be installed
on older platforms.  Apexes use their own variants that enforce
backwards compatibility.

Test: sdk_test.go
Test: TestJNIPackaging
Bug: 149591340
Change-Id: I7d72934aaee2e1326cc0ba5f29f51f14feec4521
This commit is contained in:
Colin Cross 2020-02-19 16:54:04 -08:00
parent b358ebb759
commit 82e192c3ae
21 changed files with 401 additions and 18 deletions

View File

@ -186,6 +186,7 @@ bootstrap_go_package {
"cc/rs.go", "cc/rs.go",
"cc/sanitize.go", "cc/sanitize.go",
"cc/sabi.go", "cc/sabi.go",
"cc/sdk.go",
"cc/snapshot_utils.go", "cc/snapshot_utils.go",
"cc/stl.go", "cc/stl.go",
"cc/strip.go", "cc/strip.go",

View File

@ -53,6 +53,7 @@ func init() {
AddNeverAllowRules(createLibcoreRules()...) AddNeverAllowRules(createLibcoreRules()...)
AddNeverAllowRules(createMediaRules()...) AddNeverAllowRules(createMediaRules()...)
AddNeverAllowRules(createJavaDeviceForHostRules()...) AddNeverAllowRules(createJavaDeviceForHostRules()...)
AddNeverAllowRules(createCcSdkVariantRules()...)
} }
// Add a NeverAllow rule to the set of rules to apply. // Add a NeverAllow rule to the set of rules to apply.
@ -175,6 +176,37 @@ func createJavaDeviceForHostRules() []Rule {
} }
} }
func createCcSdkVariantRules() []Rule {
sdkVersionOnlyWhitelist := []string{
// derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk.
// This sometimes works because the APEX modules that contain derive_sdk and
// derive_sdk_prefer32 suppress the platform installation rules, but fails when
// the APEX modules contain the SDK variant and the platform variant still exists.
"frameworks/base/apex/sdkextensions/derive_sdk",
}
platformVariantPropertiesWhitelist := []string{
// android_native_app_glue and libRSSupport use native_window.h but target old
// sdk versions (minimum and 9 respectively) where libnativewindow didn't exist,
// so they can't add libnativewindow to shared_libs to get the header directory
// for the platform variant. Allow them to use the platform variant
// property to set shared_libs.
"prebuilts/ndk",
"frameworks/rs",
}
return []Rule{
NeverAllow().
NotIn(sdkVersionOnlyWhitelist...).
WithMatcher("sdk_variant_only", isSetMatcherInstance).
Because("sdk_variant_only can only be used in whitelisted projects"),
NeverAllow().
NotIn(platformVariantPropertiesWhitelist...).
WithMatcher("platform.shared_libs", isSetMatcherInstance).
Because("platform variant properties can only be used in whitelisted projects"),
}
}
func neverallowMutator(ctx BottomUpMutatorContext) { func neverallowMutator(ctx BottomUpMutatorContext) {
m, ok := ctx.Module().(Module) m, ok := ctx.Module().(Module)
if !ok { if !ok {
@ -254,6 +286,18 @@ func (m *startsWithMatcher) String() string {
return ".starts-with(" + m.prefix + ")" return ".starts-with(" + m.prefix + ")"
} }
type isSetMatcher struct{}
func (m *isSetMatcher) test(value string) bool {
return value != ""
}
func (m *isSetMatcher) String() string {
return ".is-set"
}
var isSetMatcherInstance = &isSetMatcher{}
type ruleProperty struct { type ruleProperty struct {
fields []string // e.x.: Vndk.Enabled fields []string // e.x.: Vndk.Enabled
matcher ValueMatcher matcher ValueMatcher

View File

@ -249,6 +249,50 @@ var neverallowTests = []struct {
}`), }`),
}, },
}, },
// CC sdk rule tests
{
name: `"sdk_variant_only" outside whitelist`,
fs: map[string][]byte{
"Android.bp": []byte(`
cc_library {
name: "outside_whitelist",
sdk_version: "current",
sdk_variant_only: true,
}`),
},
expectedErrors: []string{
`module "outside_whitelist": violates neverallow`,
},
},
{
name: `"sdk_variant_only: false" outside whitelist`,
fs: map[string][]byte{
"Android.bp": []byte(`
cc_library {
name: "outside_whitelist",
sdk_version: "current",
sdk_variant_only: false,
}`),
},
expectedErrors: []string{
`module "outside_whitelist": violates neverallow`,
},
},
{
name: `"platform" outside whitelist`,
fs: map[string][]byte{
"Android.bp": []byte(`
cc_library {
name: "outside_whitelist",
platform: {
shared_libs: ["libfoo"],
},
}`),
},
expectedErrors: []string{
`module "outside_whitelist": violates neverallow`,
},
},
} }
func TestNeverallow(t *testing.T) { func TestNeverallow(t *testing.T) {
@ -289,6 +333,8 @@ type mockCcLibraryProperties struct {
Include_dirs []string Include_dirs []string
Vendor_available *bool Vendor_available *bool
Static_libs []string Static_libs []string
Sdk_version *string
Sdk_variant_only *bool
Vndk struct { Vndk struct {
Enabled *bool Enabled *bool
@ -305,6 +351,10 @@ type mockCcLibraryProperties struct {
Cflags []string Cflags []string
} }
} }
Platform struct {
Shared_libs []string
}
} }
type mockCcLibraryModule struct { type mockCcLibraryModule struct {

View File

@ -3350,7 +3350,7 @@ func TestApexWithApps(t *testing.T) {
} }
// JNI libraries including transitive deps are // JNI libraries including transitive deps are
for _, jni := range []string{"libjni", "libfoo"} { for _, jni := range []string{"libjni", "libfoo"} {
jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile() jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile()
// ... embedded inside APK (jnilibs.zip) // ... embedded inside APK (jnilibs.zip)
ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String()) ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
// ... and not directly inside the APEX // ... and not directly inside the APEX

View File

@ -90,6 +90,7 @@ func TestVndkApexUsesVendorVariant(t *testing.T) {
system_shared_libs: [], system_shared_libs: [],
stl: "none", stl: "none",
notice: "custom_notice", notice: "custom_notice",
sdk_version: "current",
} }
cc_library { cc_library {
name: "libprofile-clang-extras_ndk", name: "libprofile-clang-extras_ndk",
@ -98,6 +99,7 @@ func TestVndkApexUsesVendorVariant(t *testing.T) {
system_shared_libs: [], system_shared_libs: [],
stl: "none", stl: "none",
notice: "custom_notice", notice: "custom_notice",
sdk_version: "current",
} }
`, func(fs map[string][]byte, config android.Config) { `, func(fs map[string][]byte, config android.Config) {
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true) config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)

View File

@ -29,6 +29,7 @@ var (
vendorSuffix = ".vendor" vendorSuffix = ".vendor"
ramdiskSuffix = ".ramdisk" ramdiskSuffix = ".ramdisk"
recoverySuffix = ".recovery" recoverySuffix = ".recovery"
sdkSuffix = ".sdk"
) )
type AndroidMkContext interface { type AndroidMkContext interface {
@ -103,6 +104,28 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
} }
} }
} }
if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
// Make the SDK variant uninstallable so that there are not two rules to install
// to the same location.
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
// Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
// dependencies to the .sdk suffix when building a module that uses the SDK.
entries.SetString("SOONG_SDK_VARIANT_MODULES",
"$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
}
},
},
ExtraFooters: []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake &&
c.CcLibraryInterface() && c.Shared() {
// Using the SDK variant as a JNI library needs a copy of the .so that
// is not named .sdk.so so that it can be packaged into the APK with
// the right name.
fmt.Fprintln(w, "$(eval $(call copy-one-file,",
"$(LOCAL_BUILT_MODULE),",
"$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))")
}
}, },
}, },
} }
@ -393,6 +416,9 @@ func (library *toolchainLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext,
} }
func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
if installer.path == (android.InstallPath{}) {
return
}
// Soong installation is only supported for host modules. Have Make // Soong installation is only supported for host modules. Have Make
// installation trigger Soong installation. // installation trigger Soong installation.
if ctx.Target().Os.Class == android.Host { if ctx.Target().Os.Class == android.Host {

View File

@ -42,6 +42,7 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("cc_defaults", defaultsFactory) ctx.RegisterModuleType("cc_defaults", defaultsFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("sdk", sdkMutator).Parallel()
ctx.BottomUp("vndk", VndkMutator).Parallel() ctx.BottomUp("vndk", VndkMutator).Parallel()
ctx.BottomUp("link", LinkageMutator).Parallel() ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("ndk_api", NdkApiMutator).Parallel() ctx.BottomUp("ndk_api", NdkApiMutator).Parallel()
@ -208,9 +209,13 @@ type BaseProperties struct {
// Deprecated. true is the default, false is invalid. // Deprecated. true is the default, false is invalid.
Clang *bool `android:"arch_variant"` Clang *bool `android:"arch_variant"`
// Minimum sdk version supported when compiling against the ndk // Minimum sdk version supported when compiling against the ndk. Setting this property causes
// two variants to be built, one for the platform and one for apps.
Sdk_version *string Sdk_version *string
// If true, always create an sdk variant and don't create a platform variant.
Sdk_variant_only *bool
AndroidMkSharedLibs []string `blueprint:"mutated"` AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"` AndroidMkStaticLibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"` AndroidMkRuntimeLibs []string `blueprint:"mutated"`
@ -252,6 +257,16 @@ type BaseProperties struct {
SnapshotRuntimeLibs []string `blueprint:"mutated"` SnapshotRuntimeLibs []string `blueprint:"mutated"`
Installable *bool Installable *bool
// Set by factories of module types that can only be referenced from variants compiled against
// the SDK.
AlwaysSdk bool `blueprint:"mutated"`
// Variant is an SDK variant created by sdkMutator
IsSdkVariant bool `blueprint:"mutated"`
// Set when both SDK and platform variants are exported to Make to trigger renaming the SDK
// variant to have a ".sdk" suffix.
SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"`
} }
type VendorProperties struct { type VendorProperties struct {
@ -527,8 +542,11 @@ func (c *Module) Shared() bool {
} }
func (c *Module) SelectedStl() string { func (c *Module) SelectedStl() string {
if c.stl != nil {
return c.stl.Properties.SelectedStl return c.stl.Properties.SelectedStl
} }
return ""
}
func (c *Module) ToolchainLibrary() bool { func (c *Module) ToolchainLibrary() bool {
if _, ok := c.linker.(*toolchainLibraryDecorator); ok { if _, ok := c.linker.(*toolchainLibraryDecorator); ok {
@ -555,6 +573,10 @@ func (c *Module) SdkVersion() string {
return String(c.Properties.Sdk_version) return String(c.Properties.Sdk_version)
} }
func (c *Module) AlwaysSdk() bool {
return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only)
}
func (c *Module) IncludeDirs() android.Paths { func (c *Module) IncludeDirs() android.Paths {
if c.linker != nil { if c.linker != nil {
if library, ok := c.linker.(exportedFlagsProducer); ok { if library, ok := c.linker.(exportedFlagsProducer); ok {
@ -803,6 +825,17 @@ func (c *Module) UseVndk() bool {
return c.Properties.VndkVersion != "" return c.Properties.VndkVersion != ""
} }
func (c *Module) canUseSdk() bool {
return c.Os() == android.Android && !c.UseVndk() && !c.InRamdisk() && !c.InRecovery()
}
func (c *Module) UseSdk() bool {
if c.canUseSdk() {
return String(c.Properties.Sdk_version) != ""
}
return false
}
func (c *Module) isCoverageVariant() bool { func (c *Module) isCoverageVariant() bool {
return c.coverage.Properties.IsCoverageVariant return c.coverage.Properties.IsCoverageVariant
} }
@ -1060,14 +1093,11 @@ func (ctx *moduleContextImpl) header() bool {
} }
func (ctx *moduleContextImpl) canUseSdk() bool { func (ctx *moduleContextImpl) canUseSdk() bool {
return ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && !ctx.ctx.Fuchsia() return ctx.mod.canUseSdk()
} }
func (ctx *moduleContextImpl) useSdk() bool { func (ctx *moduleContextImpl) useSdk() bool {
if ctx.canUseSdk() { return ctx.mod.UseSdk()
return String(ctx.mod.Properties.Sdk_version) != ""
}
return false
} }
func (ctx *moduleContextImpl) sdkVersion() string { func (ctx *moduleContextImpl) sdkVersion() string {
@ -1386,6 +1416,8 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
c.Properties.SubName += ramdiskSuffix c.Properties.SubName += ramdiskSuffix
} else if c.InRecovery() && !c.OnlyInRecovery() { } else if c.InRecovery() && !c.OnlyInRecovery() {
c.Properties.SubName += recoverySuffix c.Properties.SubName += recoverySuffix
} else if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
c.Properties.SubName += sdkSuffix
} }
ctx := &moduleContext{ ctx := &moduleContext{

View File

@ -27,6 +27,7 @@ type GenruleExtraProperties struct {
Vendor_available *bool Vendor_available *bool
Ramdisk_available *bool Ramdisk_available *bool
Recovery_available *bool Recovery_available *bool
Sdk_version *string
} }
// cc_genrule is a genrule that can depend on other cc_* objects. // cc_genrule is a genrule that can depend on other cc_* objects.

View File

@ -1223,7 +1223,7 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
if Bool(library.Properties.Static_ndk_lib) && library.static() && if Bool(library.Properties.Static_ndk_lib) && library.static() &&
!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() &&
library.baseLinker.sanitize.isUnsanitizedVariant() && library.baseLinker.sanitize.isUnsanitizedVariant() &&
!library.buildStubs() { !library.buildStubs() && ctx.sdkVersion() == "" {
installPath := getNdkSysrootBase(ctx).Join( installPath := getNdkSysrootBase(ctx).Join(
ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base()) ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())

View File

@ -45,12 +45,14 @@ type LinkableInterface interface {
InRecovery() bool InRecovery() bool
OnlyInRecovery() bool OnlyInRecovery() bool
UseSdk() bool
UseVndk() bool UseVndk() bool
MustUseVendorVariant() bool MustUseVendorVariant() bool
IsVndk() bool IsVndk() bool
HasVendorVariant() bool HasVendorVariant() bool
SdkVersion() string SdkVersion() string
AlwaysSdk() bool
ToolchainLibrary() bool ToolchainLibrary() bool
NdkPrebuiltStl() bool NdkPrebuiltStl() bool

View File

@ -158,6 +158,13 @@ type BaseLinkerProperties struct {
// the ramdisk variant of the C/C++ module. // the ramdisk variant of the C/C++ module.
Exclude_static_libs []string Exclude_static_libs []string
} }
Platform struct {
// list of shared libs that should be use to build the platform variant
// of a module that sets sdk_version. This should rarely be necessary,
// in most cases the same libraries are available for the SDK and platform
// variants.
Shared_libs []string
}
} }
// make android::build:GetBuildNumber() available containing the build ID. // make android::build:GetBuildNumber() available containing the build ID.
@ -255,6 +262,10 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs) deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
} }
if !ctx.useSdk() {
deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Platform.Shared_libs...)
}
if ctx.toolchain().Bionic() { if ctx.toolchain().Bionic() {
// libclang_rt.builtins and libatomic have to be last on the command line // libclang_rt.builtins and libatomic have to be last on the command line
if !Bool(linker.Properties.No_libcrt) { if !Bool(linker.Properties.No_libcrt) {

View File

@ -381,6 +381,9 @@ func newStubLibrary() *Module {
module.linker = stub module.linker = stub
module.installer = stub module.installer = stub
module.Properties.AlwaysSdk = true
module.Properties.Sdk_version = StringPtr("current")
module.AddProperties(&stub.properties, &library.MutatedProperties) module.AddProperties(&stub.properties, &library.MutatedProperties)
return module return module

View File

@ -76,6 +76,8 @@ func NdkPrebuiltObjectFactory() android.Module {
baseLinker: NewBaseLinker(nil), baseLinker: NewBaseLinker(nil),
}, },
} }
module.Properties.AlwaysSdk = true
module.Properties.Sdk_version = StringPtr("current")
module.Properties.HideFromMake = true module.Properties.HideFromMake = true
return module.Init() return module.Init()
} }
@ -115,10 +117,9 @@ func NdkPrebuiltSharedStlFactory() android.Module {
libraryDecorator: library, libraryDecorator: library,
} }
module.installer = nil module.installer = nil
minVersionString := "minimum" module.Properties.Sdk_version = StringPtr("minimum")
noStlString := "none" module.Properties.AlwaysSdk = true
module.Properties.Sdk_version = &minVersionString module.stl.Properties.Stl = StringPtr("none")
module.stl.Properties.Stl = &noStlString
return module.Init() return module.Init()
} }
@ -135,6 +136,9 @@ func NdkPrebuiltStaticStlFactory() android.Module {
} }
module.installer = nil module.installer = nil
module.Properties.HideFromMake = true module.Properties.HideFromMake = true
module.Properties.AlwaysSdk = true
module.Properties.Sdk_version = StringPtr("current")
module.stl.Properties.Stl = StringPtr("none")
module.ModuleBase.EnableNativeBridgeSupportByDefault() module.ModuleBase.EnableNativeBridgeSupportByDefault()
return module.Init() return module.Init()
} }

65
cc/sdk.go Normal file
View File

@ -0,0 +1,65 @@
// Copyright 2020 Google Inc. All rights reserved.
//
// 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 cc
import (
"android/soong/android"
"android/soong/genrule"
)
// sdkMutator sets a creates a platform and an SDK variant for modules
// that set sdk_version, and ignores sdk_version for the platform
// variant. The SDK variant will be used for embedding in APKs
// that may be installed on older platforms. Apexes use their own
// variants that enforce backwards compatibility.
func sdkMutator(ctx android.BottomUpMutatorContext) {
if ctx.Os() != android.Android {
return
}
switch m := ctx.Module().(type) {
case LinkableInterface:
if m.AlwaysSdk() {
if !m.UseSdk() {
ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
}
ctx.CreateVariations("sdk")
} else if m.UseSdk() {
modules := ctx.CreateVariations("", "sdk")
modules[0].(*Module).Properties.Sdk_version = nil
modules[1].(*Module).Properties.IsSdkVariant = true
if ctx.Config().UnbundledBuild() {
modules[0].(*Module).Properties.HideFromMake = true
} else {
modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
modules[1].(*Module).Properties.PreventInstall = true
}
ctx.AliasVariation("")
} else {
ctx.CreateVariations("")
ctx.AliasVariation("")
}
case *genrule.Module:
if p, ok := m.Extra.(*GenruleExtraProperties); ok {
if String(p.Sdk_version) != "" {
ctx.CreateVariations("", "sdk")
} else {
ctx.CreateVariations("")
}
ctx.AliasVariation("")
}
}
}

102
cc/sdk_test.go Normal file
View File

@ -0,0 +1,102 @@
// Copyright 2020 Google Inc. All rights reserved.
//
// 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 cc
import (
"testing"
"android/soong/android"
)
func TestSdkMutator(t *testing.T) {
bp := `
cc_library {
name: "libsdk",
shared_libs: ["libsdkdep"],
sdk_version: "current",
stl: "c++_shared",
}
cc_library {
name: "libsdkdep",
sdk_version: "current",
stl: "c++_shared",
}
cc_library {
name: "libplatform",
shared_libs: ["libsdk"],
stl: "libc++",
}
cc_binary {
name: "platformbinary",
shared_libs: ["libplatform"],
stl: "libc++",
}
cc_binary {
name: "sdkbinary",
shared_libs: ["libsdk"],
sdk_version: "current",
stl: "libc++",
}
`
assertDep := func(t *testing.T, from, to android.TestingModule) {
t.Helper()
found := false
var toFile android.Path
m := to.Module().(*Module)
if toc := m.Toc(); toc.Valid() {
toFile = toc.Path()
} else {
toFile = m.outputFile.Path()
}
rule := from.Description("link")
for _, dep := range rule.Implicits {
if dep.String() == toFile.String() {
found = true
}
}
if !found {
t.Errorf("expected %q in %q", toFile.String(), rule.Implicits.Strings())
}
}
ctx := testCc(t, bp)
libsdkNDK := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_sdk_shared")
libsdkPlatform := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_shared")
libsdkdepNDK := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_sdk_shared")
libsdkdepPlatform := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_shared")
libplatform := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared")
platformbinary := ctx.ModuleForTests("platformbinary", "android_arm64_armv8-a")
sdkbinary := ctx.ModuleForTests("sdkbinary", "android_arm64_armv8-a_sdk")
libcxxNDK := ctx.ModuleForTests("ndk_libc++_shared", "android_arm64_armv8-a_sdk_shared")
libcxxPlatform := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared")
assertDep(t, libsdkNDK, libsdkdepNDK)
assertDep(t, libsdkPlatform, libsdkdepPlatform)
assertDep(t, libplatform, libsdkPlatform)
assertDep(t, platformbinary, libplatform)
assertDep(t, sdkbinary, libsdkNDK)
assertDep(t, libsdkNDK, libcxxNDK)
assertDep(t, libsdkPlatform, libcxxPlatform)
}

View File

@ -115,9 +115,13 @@ func (stl *stl) begin(ctx BaseModuleContext) {
switch s { switch s {
case "libc++", "libc++_static": case "libc++", "libc++_static":
return s return s
case "c++_shared":
return "libc++"
case "c++_static":
return "libc++_static"
case "none": case "none":
return "" return ""
case "": case "", "system":
if ctx.static() { if ctx.static() {
return "libc++_static" return "libc++_static"
} else { } else {

View File

@ -138,6 +138,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
name: "libgcc_stripped", name: "libgcc_stripped",
vendor_available: true, vendor_available: true,
recovery_available: true, recovery_available: true,
sdk_version: "current",
src: "", src: "",
} }
@ -155,6 +156,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
llndk_library { llndk_library {
name: "libc", name: "libc",
symbol_file: "", symbol_file: "",
sdk_version: "current",
} }
cc_library { cc_library {
name: "libm", name: "libm",
@ -174,6 +176,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
llndk_library { llndk_library {
name: "libm", name: "libm",
symbol_file: "", symbol_file: "",
sdk_version: "current",
} }
cc_library { cc_library {
name: "libdl", name: "libdl",
@ -193,6 +196,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
llndk_library { llndk_library {
name: "libdl", name: "libdl",
symbol_file: "", symbol_file: "",
sdk_version: "current",
} }
cc_library { cc_library {
name: "libft2", name: "libft2",
@ -205,6 +209,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
name: "libft2", name: "libft2",
symbol_file: "", symbol_file: "",
vendor_available: false, vendor_available: false,
sdk_version: "current",
} }
cc_library { cc_library {
name: "libc++_static", name: "libc++_static",
@ -336,6 +341,16 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
sdk_version: "27", sdk_version: "27",
} }
ndk_prebuilt_object {
name: "ndk_crtbegin_dynamic.27",
sdk_version: "27",
}
ndk_prebuilt_object {
name: "ndk_crtend_android.27",
sdk_version: "27",
}
ndk_prebuilt_shared_stl { ndk_prebuilt_shared_stl {
name: "ndk_libc++_shared", name: "ndk_libc++_shared",
} }

View File

@ -67,6 +67,7 @@ func ToolchainLibraryFactory() android.Module {
module.stl = nil module.stl = nil
module.sanitize = nil module.sanitize = nil
module.installer = nil module.installer = nil
module.Properties.Sdk_version = StringPtr("current")
return module.Init() return module.Init()
} }

View File

@ -204,6 +204,13 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
for _, jniTarget := range ctx.MultiTargets() { for _, jniTarget := range ctx.MultiTargets() {
variation := append(jniTarget.Variations(), variation := append(jniTarget.Variations(),
blueprint.Variation{Mutator: "link", Variation: "shared"}) blueprint.Variation{Mutator: "link", Variation: "shared"})
// If the app builds against an Android SDK use the SDK variant of JNI dependencies
// unless jni_uses_platform_apis is set.
if a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform &&
!Bool(a.appProperties.Jni_uses_platform_apis) {
variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
}
ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...) ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
} }

View File

@ -791,6 +791,7 @@ func TestJNIABI(t *testing.T) {
cc_library { cc_library {
name: "libjni", name: "libjni",
system_shared_libs: [], system_shared_libs: [],
sdk_version: "current",
stl: "none", stl: "none",
} }
@ -928,26 +929,26 @@ func TestJNIPackaging(t *testing.T) {
android_test { android_test {
name: "test", name: "test",
sdk_version: "core_platform", sdk_version: "current",
jni_libs: ["libjni"], jni_libs: ["libjni"],
} }
android_test { android_test {
name: "test_noembed", name: "test_noembed",
sdk_version: "core_platform", sdk_version: "current",
jni_libs: ["libjni"], jni_libs: ["libjni"],
use_embedded_native_libs: false, use_embedded_native_libs: false,
} }
android_test_helper_app { android_test_helper_app {
name: "test_helper", name: "test_helper",
sdk_version: "core_platform", sdk_version: "current",
jni_libs: ["libjni"], jni_libs: ["libjni"],
} }
android_test_helper_app { android_test_helper_app {
name: "test_helper_noembed", name: "test_helper_noembed",
sdk_version: "core_platform", sdk_version: "current",
jni_libs: ["libjni"], jni_libs: ["libjni"],
use_embedded_native_libs: false, use_embedded_native_libs: false,
} }
@ -979,6 +980,10 @@ func TestJNIPackaging(t *testing.T) {
if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w { if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w {
t.Errorf("expected jni compressed %v, got %v", w, g) t.Errorf("expected jni compressed %v, got %v", w, g)
} }
if !strings.Contains(jniLibZip.Implicits[0].String(), "_sdk_") {
t.Errorf("expected input %q to use sdk variant", jniLibZip.Implicits[0].String())
}
} }
}) })
} }

View File

@ -164,6 +164,10 @@ func (mod *Module) OnlyInRecovery() bool {
return false return false
} }
func (mod *Module) UseSdk() bool {
return false
}
func (mod *Module) UseVndk() bool { func (mod *Module) UseVndk() bool {
return false return false
} }
@ -184,6 +188,10 @@ func (mod *Module) SdkVersion() string {
return "" return ""
} }
func (mod *Module) AlwaysSdk() bool {
return false
}
func (mod *Module) ToolchainLibrary() bool { func (mod *Module) ToolchainLibrary() bool {
return false return false
} }