Merge changes from topic "soong_jni"

* changes:
  Add android_test_helper_app
  Add support for android_app_certificate modules
  Add support for JNI libraries to android_app modules
This commit is contained in:
Treehugger Robot 2018-10-09 21:50:40 +00:00 committed by Gerrit Code Review
commit 08914b9c98
10 changed files with 410 additions and 43 deletions

View file

@ -219,6 +219,7 @@ bootstrap_go_package {
"blueprint-pathtools",
"soong",
"soong-android",
"soong-cc",
"soong-genrule",
"soong-java-config",
"soong-tradefed",

View file

@ -232,8 +232,8 @@ func TestArchConfig(buildDir string, env map[string]string) Config {
config.Targets = map[OsClass][]Target{
Device: []Target{
{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true}},
{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true}},
{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Native: true, Abi: []string{"arm64-v8a"}}},
{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Native: true, Abi: []string{"armeabi-v7a"}}},
},
Host: []Target{
{BuildOs, Arch{ArchType: X86_64}},

View file

@ -140,6 +140,7 @@ func init() {
"LOCAL_DX_FLAGS": "dxflags",
"LOCAL_JAVA_LIBRARIES": "libs",
"LOCAL_STATIC_JAVA_LIBRARIES": "static_libs",
"LOCAL_JNI_SHARED_LIBRARIES": "jni_libs",
"LOCAL_AAPT_FLAGS": "aaptflags",
"LOCAL_PACKAGE_SPLITS": "package_splits",
"LOCAL_COMPATIBILITY_SUITE": "test_suites",
@ -154,6 +155,7 @@ func init() {
// java_library_static to android_library.
"LOCAL_SHARED_ANDROID_LIBRARIES": "android_libs",
"LOCAL_STATIC_ANDROID_LIBRARIES": "android_static_libs",
"LOCAL_ADDITIONAL_CERTIFICATES": "additional_certificates",
})
addStandardProperties(bpparser.BoolType,

View file

@ -243,6 +243,10 @@ func (app *AndroidApp) AndroidMk() android.AndroidMkData {
if len(app.appProperties.Overrides) > 0 {
fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES := "+strings.Join(app.appProperties.Overrides, " "))
}
for _, jniLib := range app.installJniLibs {
fmt.Fprintln(w, "LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), "+=", jniLib.name)
}
},
},
}
@ -267,6 +271,21 @@ func (a *AndroidTest) AndroidMk() android.AndroidMkData {
return data
}
func (a *AndroidTestHelperApp) AndroidMk() android.AndroidMkData {
data := a.AndroidApp.AndroidMk()
data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
fmt.Fprintln(w, "LOCAL_MODULE_TAGS := tests")
if len(a.appTestHelperAppProperties.Test_suites) > 0 {
fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
strings.Join(a.appTestHelperAppProperties.Test_suites, " "))
} else {
fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite")
}
})
return data
}
func (a *AndroidLibrary) AndroidMk() android.AndroidMkData {
data := a.Library.AndroidMk()

View file

@ -19,26 +19,30 @@ package java
import (
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/cc"
"android/soong/tradefed"
)
func init() {
android.RegisterModuleType("android_app", AndroidAppFactory)
android.RegisterModuleType("android_test", AndroidTestFactory)
android.RegisterModuleType("android_test_helper_app", AndroidTestHelperAppFactory)
android.RegisterModuleType("android_app_certificate", AndroidAppCertificateFactory)
}
// AndroidManifest.xml merging
// package splits
type appProperties struct {
// path to a certificate, or the name of a certificate in the default
// certificate directory, or blank to use the default product certificate
// The name of a certificate in the default certificate directory, blank to use the default product certificate,
// or an android_app_certificate module name in the form ":module".
Certificate *string
// paths to extra certificates to sign the apk with
// Names of extra android_app_certificate modules to sign the apk with in the form ":module".
Additional_certificates []string
// If set, create package-export.apk, which other packages can
@ -59,6 +63,11 @@ type appProperties struct {
// binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
// from PRODUCT_PACKAGES.
Overrides []string
// list of native libraries that will be provided in or alongside the resulting jar
Jni_libs []string `android:"arch_variant"`
EmbedJNI bool `blueprint:"mutated"`
}
type AndroidApp struct {
@ -70,6 +79,8 @@ type AndroidApp struct {
appProperties appProperties
extraLinkFlags []string
installJniLibs []jniLib
}
func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths {
@ -92,9 +103,36 @@ type certificate struct {
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
a.Module.deps(ctx)
if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
a.aapt.deps(ctx, sdkContext(a))
}
for _, jniTarget := range ctx.MultiTargets() {
variation := []blueprint.Variation{
{Mutator: "arch", Variation: jniTarget.String()},
{Mutator: "link", Variation: "shared"},
}
tag := &jniDependencyTag{
target: jniTarget,
}
ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
}
cert := android.SrcIsModule(String(a.appProperties.Certificate))
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
}
for _, cert := range a.appProperties.Additional_certificates {
cert = android.SrcIsModule(cert)
if cert != "" {
ctx.AddDependency(ctx.Module(), certificateTag, cert)
} else {
ctx.PropertyErrorf("additional_certificates",
`must be names of android_app_certificate modules in the form ":module"`)
}
}
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@ -150,35 +188,45 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
a.Module.compile(ctx, a.aaptSrcJar)
}
c := String(a.appProperties.Certificate)
switch {
case c == "":
pem, key := ctx.Config().DefaultAppCertificate(ctx)
a.certificate = certificate{pem, key}
case strings.ContainsRune(c, '/'):
a.certificate = certificate{
android.PathForSource(ctx, c+".x509.pem"),
android.PathForSource(ctx, c+".pk8"),
}
default:
defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
a.certificate = certificate{
defaultDir.Join(ctx, c+".x509.pem"),
defaultDir.Join(ctx, c+".pk8"),
}
}
certificates := []certificate{a.certificate}
for _, c := range a.appProperties.Additional_certificates {
certificates = append(certificates, certificate{
android.PathForSource(ctx, c+".x509.pem"),
android.PathForSource(ctx, c+".pk8"),
})
}
packageFile := android.PathForModuleOut(ctx, "package.apk")
CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
var certificates []certificate
var jniJarFile android.WritablePath
jniLibs, certificateDeps := a.collectAppDeps(ctx)
if len(jniLibs) > 0 {
embedJni := ctx.Config().UnbundledBuild() || a.appProperties.EmbedJNI
if embedJni {
jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
TransformJniLibsToJar(ctx, jniJarFile, jniLibs)
} else {
a.installJniLibs = jniLibs
}
}
if ctx.Failed() {
return
}
cert := String(a.appProperties.Certificate)
certModule := android.SrcIsModule(cert)
if certModule != "" {
a.certificate = certificateDeps[0]
certificateDeps = certificateDeps[1:]
} else if cert != "" {
defaultDir := ctx.Config().DefaultAppCertificateDir(ctx)
a.certificate = certificate{
defaultDir.Join(ctx, cert+".x509.pem"),
defaultDir.Join(ctx, cert+".pk8"),
}
} else {
pem, key := ctx.Config().DefaultAppCertificate(ctx)
a.certificate = certificate{pem, key}
}
certificates = append([]certificate{a.certificate}, certificateDeps...)
CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, a.outputFile, certificates)
a.outputFile = packageFile
@ -192,6 +240,42 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) {
}
}
func (a *AndroidApp) collectAppDeps(ctx android.ModuleContext) ([]jniLib, []certificate) {
var jniLibs []jniLib
var certificates []certificate
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
if jniTag, ok := tag.(*jniDependencyTag); ok {
if dep, ok := module.(*cc.Module); ok {
lib := dep.OutputFile()
if lib.Valid() {
jniLibs = append(jniLibs, jniLib{
name: ctx.OtherModuleName(module),
path: lib.Path(),
target: jniTag.target,
})
} else {
ctx.ModuleErrorf("dependency %q missing output file", otherName)
}
} else {
ctx.ModuleErrorf("jni_libs dependency %q must be a cc library", otherName)
}
} else if tag == certificateTag {
if dep, ok := module.(*AndroidAppCertificate); ok {
certificates = append(certificates, dep.certificate)
} else {
ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName)
}
}
})
return jniLibs, certificates
}
func AndroidAppFactory() android.Module {
module := &AndroidApp{}
@ -212,7 +296,9 @@ func AndroidAppFactory() android.Module {
return class == android.Device && ctx.Config().DevicePrefer32BitApps()
})
InitJavaModule(module, android.DeviceSupported)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
return module
}
@ -258,6 +344,7 @@ func AndroidTestFactory() android.Module {
module.Module.properties.Instrument = true
module.Module.properties.Installable = proptools.BoolPtr(true)
module.appProperties.EmbedJNI = true
module.AddProperties(
&module.Module.properties,
@ -268,6 +355,69 @@ func AndroidTestFactory() android.Module {
&module.appTestProperties,
&module.testProperties)
InitJavaModule(module, android.DeviceSupported)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
return module
}
type appTestHelperAppProperties struct {
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
Test_suites []string `android:"arch_variant"`
}
type AndroidTestHelperApp struct {
AndroidApp
appTestHelperAppProperties appTestHelperAppProperties
}
func AndroidTestHelperAppFactory() android.Module {
module := &AndroidTestHelperApp{}
module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
module.Module.properties.Installable = proptools.BoolPtr(true)
module.appProperties.EmbedJNI = true
module.AddProperties(
&module.Module.properties,
&module.Module.deviceProperties,
&module.Module.protoProperties,
&module.aaptProperties,
&module.appProperties,
&module.appTestHelperAppProperties)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
return module
}
type AndroidAppCertificate struct {
android.ModuleBase
properties AndroidAppCertificateProperties
certificate certificate
}
type AndroidAppCertificateProperties struct {
// Name of the certificate files. Extensions .x509.pem and .pk8 will be added to the name.
Certificate *string
}
func AndroidAppCertificateFactory() android.Module {
module := &AndroidAppCertificate{}
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
return module
}
func (c *AndroidAppCertificate) DepsMutator(ctx android.BottomUpMutatorContext) {
}
func (c *AndroidAppCertificate) GenerateAndroidBuildActions(ctx android.ModuleContext) {
cert := String(c.properties.Certificate)
c.certificate = certificate{
android.PathForModuleSrc(ctx, cert+".x509.pem"),
android.PathForModuleSrc(ctx, cert+".pk8"),
}
}

View file

@ -19,9 +19,11 @@ package java
// functions.
import (
"path/filepath"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
)
@ -61,16 +63,18 @@ var combineApk = pctx.AndroidStaticRule("combineApk",
})
func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
resJarFile, dexJarFile android.Path, certificates []certificate) {
// TODO(ccross): JNI libs
resJarFile, jniJarFile, dexJarFile android.Path, certificates []certificate) {
unsignedApk := android.PathForModuleOut(ctx, "unsigned.apk")
inputs := android.Paths{resJarFile}
var inputs android.Paths
if dexJarFile != nil {
inputs = append(inputs, dexJarFile)
}
inputs = append(inputs, resJarFile)
if jniJarFile != nil {
inputs = append(inputs, jniJarFile)
}
ctx.Build(pctx, android.BuildParams{
Rule: combineApk,
@ -132,3 +136,37 @@ func BuildAAR(ctx android.ModuleContext, outputFile android.WritablePath,
},
})
}
func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.WritablePath,
jniLibs []jniLib) {
var deps android.Paths
jarArgs := []string{
"-j", // junk paths, they will be added back with -P arguments
}
if !ctx.Config().UnbundledBuild() {
jarArgs = append(jarArgs, "-L 0")
}
for _, j := range jniLibs {
deps = append(deps, j.path)
jarArgs = append(jarArgs,
"-P "+targetToJniDir(j.target),
"-f "+j.path.String())
}
ctx.Build(pctx, android.BuildParams{
Rule: zip,
Description: "zip jni libs",
Output: outputFile,
Implicits: deps,
Args: map[string]string{
"jarArgs": strings.Join(proptools.NinjaAndShellEscape(jarArgs), " "),
},
})
}
func targetToJniDir(target android.Target) string {
return filepath.Join("lib", target.Arch.Abi[0])
}

View file

@ -17,6 +17,7 @@ package java
import (
"android/soong/android"
"fmt"
"path/filepath"
"reflect"
"sort"
"strings"
@ -338,3 +339,118 @@ func TestAppSdkVersion(t *testing.T) {
}
}
}
func TestJNI(t *testing.T) {
ctx := testJava(t, `
toolchain_library {
name: "libcompiler_rt-extras",
src: "",
}
toolchain_library {
name: "libatomic",
src: "",
}
toolchain_library {
name: "libgcc",
src: "",
}
toolchain_library {
name: "libclang_rt.builtins-aarch64-android",
src: "",
}
toolchain_library {
name: "libclang_rt.builtins-arm-android",
src: "",
}
cc_object {
name: "crtbegin_so",
stl: "none",
}
cc_object {
name: "crtend_so",
stl: "none",
}
cc_library {
name: "libjni",
system_shared_libs: [],
stl: "none",
}
android_test {
name: "test",
no_framework_libs: true,
jni_libs: ["libjni"],
}
android_test {
name: "test_first",
no_framework_libs: true,
compile_multilib: "first",
jni_libs: ["libjni"],
}
android_test {
name: "test_both",
no_framework_libs: true,
compile_multilib: "both",
jni_libs: ["libjni"],
}
android_test {
name: "test_32",
no_framework_libs: true,
compile_multilib: "32",
jni_libs: ["libjni"],
}
android_test {
name: "test_64",
no_framework_libs: true,
compile_multilib: "64",
jni_libs: ["libjni"],
}
`)
// check the existence of the internal modules
ctx.ModuleForTests("test", "android_common")
ctx.ModuleForTests("test_first", "android_common")
ctx.ModuleForTests("test_both", "android_common")
ctx.ModuleForTests("test_32", "android_common")
ctx.ModuleForTests("test_64", "android_common")
testCases := []struct {
name string
abis []string
}{
{"test", []string{"arm64-v8a"}},
{"test_first", []string{"arm64-v8a"}},
{"test_both", []string{"arm64-v8a", "armeabi-v7a"}},
{"test_32", []string{"armeabi-v7a"}},
{"test_64", []string{"arm64-v8a"}},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
app := ctx.ModuleForTests(test.name, "android_common")
jniLibZip := app.Output("jnilibs.zip")
var abis []string
args := strings.Fields(jniLibZip.Args["jarArgs"])
for i := 0; i < len(args); i++ {
if args[i] == "-P" {
abis = append(abis, filepath.Base(args[i+1]))
i++
}
}
if !reflect.DeepEqual(abis, test.abis) {
t.Errorf("want abis %v, got %v", test.abis, abis)
}
})
}
}

View file

@ -109,6 +109,15 @@ var (
},
"jarArgs")
zip = pctx.AndroidStaticRule("zip",
blueprint.RuleParams{
Command: `${config.SoongZipCmd} -o $out @$out.rsp`,
CommandDeps: []string{"${config.SoongZipCmd}"},
Rspfile: "$out.rsp",
RspfileContent: "$jarArgs",
},
"jarArgs")
combineJar = pctx.AndroidStaticRule("combineJar",
blueprint.RuleParams{
Command: `${config.MergeZipsCmd} --ignore-duplicates -j $jarArgs $out $in`,

View file

@ -95,9 +95,6 @@ type CompilerProperties struct {
// list of java libraries that will be compiled into the resulting jar
Static_libs []string `android:"arch_variant"`
// list of native libraries that will be provided in or alongside the resulting jar
Jni_libs []string `android:"arch_variant"`
// manifest file to be included in resulting jar
Manifest *string
@ -365,6 +362,11 @@ type dependencyTag struct {
name string
}
type jniDependencyTag struct {
blueprint.BaseDependencyTag
target android.Target
}
var (
staticLibTag = dependencyTag{name: "staticlib"}
libTag = dependencyTag{name: "javalib"}
@ -375,6 +377,7 @@ var (
frameworkApkTag = dependencyTag{name: "framework-apk"}
kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"}
proguardRaiseTag = dependencyTag{name: "proguard-raise"}
certificateTag = dependencyTag{name: "certificate"}
)
type sdkDep struct {
@ -389,6 +392,12 @@ type sdkDep struct {
aidl android.Path
}
type jniLib struct {
name string
path android.Path
target android.Target
}
func (j *Module) shouldInstrument(ctx android.BaseContext) bool {
return j.properties.Instrument && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
}
@ -597,6 +606,7 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) {
ctx.AddFarVariationDependencies([]blueprint.Variation{
{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant},
}, annoTag, j.properties.Annotation_processors...)
android.ExtractSourcesDeps(ctx, j.properties.Srcs)
android.ExtractSourcesDeps(ctx, j.properties.Exclude_srcs)
android.ExtractSourcesDeps(ctx, j.properties.Java_resources)
@ -787,6 +797,15 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
if _, ok := tag.(*jniDependencyTag); ok {
// Handled by AndroidApp.collectAppDeps
return
}
if tag == certificateTag {
// Handled by AndroidApp.collectAppDeps
return
}
if to, ok := module.(*Library); ok {
switch tag {
case bootClasspathTag, libTag, staticLibTag:

View file

@ -15,8 +15,6 @@
package java
import (
"android/soong/android"
"android/soong/genrule"
"fmt"
"io/ioutil"
"os"
@ -27,6 +25,10 @@ import (
"testing"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/cc"
"android/soong/genrule"
)
var buildDir string
@ -73,6 +75,7 @@ func testContext(config android.Config, bp string,
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
ctx.RegisterModuleType("android_library", android.ModuleFactoryAdaptor(AndroidLibraryFactory))
ctx.RegisterModuleType("android_test", android.ModuleFactoryAdaptor(AndroidTestFactory))
ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory))
ctx.RegisterModuleType("java_library_host", android.ModuleFactoryAdaptor(LibraryHostFactory))
@ -95,6 +98,16 @@ func testContext(config android.Config, bp string,
ctx.TopDown("java_sdk_library", sdkLibraryMutator).Parallel()
})
ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
// Register module types and mutators from cc needed for JNI testing
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("link", cc.LinkageMutator).Parallel()
ctx.BottomUp("begin", cc.BeginMutator).Parallel()
})
ctx.Register()
extraModules := []string{