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/sanitize.go",
"cc/sabi.go",
"cc/sdk.go",
"cc/snapshot_utils.go",
"cc/stl.go",
"cc/strip.go",

View File

@ -53,6 +53,7 @@ func init() {
AddNeverAllowRules(createLibcoreRules()...)
AddNeverAllowRules(createMediaRules()...)
AddNeverAllowRules(createJavaDeviceForHostRules()...)
AddNeverAllowRules(createCcSdkVariantRules()...)
}
// 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) {
m, ok := ctx.Module().(Module)
if !ok {
@ -254,6 +286,18 @@ func (m *startsWithMatcher) String() string {
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 {
fields []string // e.x.: Vndk.Enabled
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) {
@ -289,6 +333,8 @@ type mockCcLibraryProperties struct {
Include_dirs []string
Vendor_available *bool
Static_libs []string
Sdk_version *string
Sdk_variant_only *bool
Vndk struct {
Enabled *bool
@ -305,6 +351,10 @@ type mockCcLibraryProperties struct {
Cflags []string
}
}
Platform struct {
Shared_libs []string
}
}
type mockCcLibraryModule struct {

View File

@ -3350,7 +3350,7 @@ func TestApexWithApps(t *testing.T) {
}
// JNI libraries including transitive deps are
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)
ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
// ... and not directly inside the APEX

View File

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

View File

@ -29,6 +29,7 @@ var (
vendorSuffix = ".vendor"
ramdiskSuffix = ".ramdisk"
recoverySuffix = ".recovery"
sdkSuffix = ".sdk"
)
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) {
if installer.path == (android.InstallPath{}) {
return
}
// Soong installation is only supported for host modules. Have Make
// installation trigger Soong installation.
if ctx.Target().Os.Class == android.Host {

View File

@ -42,6 +42,7 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("cc_defaults", defaultsFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("sdk", sdkMutator).Parallel()
ctx.BottomUp("vndk", VndkMutator).Parallel()
ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("ndk_api", NdkApiMutator).Parallel()
@ -208,9 +209,13 @@ type BaseProperties struct {
// Deprecated. true is the default, false is invalid.
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
// If true, always create an sdk variant and don't create a platform variant.
Sdk_variant_only *bool
AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
@ -252,6 +257,16 @@ type BaseProperties struct {
SnapshotRuntimeLibs []string `blueprint:"mutated"`
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 {
@ -527,7 +542,10 @@ func (c *Module) Shared() bool {
}
func (c *Module) SelectedStl() string {
return c.stl.Properties.SelectedStl
if c.stl != nil {
return c.stl.Properties.SelectedStl
}
return ""
}
func (c *Module) ToolchainLibrary() bool {
@ -555,6 +573,10 @@ func (c *Module) SdkVersion() string {
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 {
if c.linker != nil {
if library, ok := c.linker.(exportedFlagsProducer); ok {
@ -803,6 +825,17 @@ func (c *Module) UseVndk() bool {
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 {
return c.coverage.Properties.IsCoverageVariant
}
@ -1060,14 +1093,11 @@ func (ctx *moduleContextImpl) header() 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 {
if ctx.canUseSdk() {
return String(ctx.mod.Properties.Sdk_version) != ""
}
return false
return ctx.mod.UseSdk()
}
func (ctx *moduleContextImpl) sdkVersion() string {
@ -1386,6 +1416,8 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
c.Properties.SubName += ramdiskSuffix
} else if c.InRecovery() && !c.OnlyInRecovery() {
c.Properties.SubName += recoverySuffix
} else if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
c.Properties.SubName += sdkSuffix
}
ctx := &moduleContext{

View File

@ -27,6 +27,7 @@ type GenruleExtraProperties struct {
Vendor_available *bool
Ramdisk_available *bool
Recovery_available *bool
Sdk_version *string
}
// 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() &&
!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() &&
library.baseLinker.sanitize.isUnsanitizedVariant() &&
!library.buildStubs() {
!library.buildStubs() && ctx.sdkVersion() == "" {
installPath := getNdkSysrootBase(ctx).Join(
ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())

View File

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

View File

@ -158,6 +158,13 @@ type BaseLinkerProperties struct {
// the ramdisk variant of the C/C++ module.
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.
@ -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)
}
if !ctx.useSdk() {
deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Platform.Shared_libs...)
}
if ctx.toolchain().Bionic() {
// libclang_rt.builtins and libatomic have to be last on the command line
if !Bool(linker.Properties.No_libcrt) {

View File

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

View File

@ -76,6 +76,8 @@ func NdkPrebuiltObjectFactory() android.Module {
baseLinker: NewBaseLinker(nil),
},
}
module.Properties.AlwaysSdk = true
module.Properties.Sdk_version = StringPtr("current")
module.Properties.HideFromMake = true
return module.Init()
}
@ -115,10 +117,9 @@ func NdkPrebuiltSharedStlFactory() android.Module {
libraryDecorator: library,
}
module.installer = nil
minVersionString := "minimum"
noStlString := "none"
module.Properties.Sdk_version = &minVersionString
module.stl.Properties.Stl = &noStlString
module.Properties.Sdk_version = StringPtr("minimum")
module.Properties.AlwaysSdk = true
module.stl.Properties.Stl = StringPtr("none")
return module.Init()
}
@ -135,6 +136,9 @@ func NdkPrebuiltStaticStlFactory() android.Module {
}
module.installer = nil
module.Properties.HideFromMake = true
module.Properties.AlwaysSdk = true
module.Properties.Sdk_version = StringPtr("current")
module.stl.Properties.Stl = StringPtr("none")
module.ModuleBase.EnableNativeBridgeSupportByDefault()
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 {
case "libc++", "libc++_static":
return s
case "c++_shared":
return "libc++"
case "c++_static":
return "libc++_static"
case "none":
return ""
case "":
case "", "system":
if ctx.static() {
return "libc++_static"
} else {

View File

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

View File

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

View File

@ -204,6 +204,13 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
for _, jniTarget := range ctx.MultiTargets() {
variation := append(jniTarget.Variations(),
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...)
}

View File

@ -791,6 +791,7 @@ func TestJNIABI(t *testing.T) {
cc_library {
name: "libjni",
system_shared_libs: [],
sdk_version: "current",
stl: "none",
}
@ -928,26 +929,26 @@ func TestJNIPackaging(t *testing.T) {
android_test {
name: "test",
sdk_version: "core_platform",
sdk_version: "current",
jni_libs: ["libjni"],
}
android_test {
name: "test_noembed",
sdk_version: "core_platform",
sdk_version: "current",
jni_libs: ["libjni"],
use_embedded_native_libs: false,
}
android_test_helper_app {
name: "test_helper",
sdk_version: "core_platform",
sdk_version: "current",
jni_libs: ["libjni"],
}
android_test_helper_app {
name: "test_helper_noembed",
sdk_version: "core_platform",
sdk_version: "current",
jni_libs: ["libjni"],
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 {
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
}
func (mod *Module) UseSdk() bool {
return false
}
func (mod *Module) UseVndk() bool {
return false
}
@ -184,6 +188,10 @@ func (mod *Module) SdkVersion() string {
return ""
}
func (mod *Module) AlwaysSdk() bool {
return false
}
func (mod *Module) ToolchainLibrary() bool {
return false
}