From a4f08813a34418a07aa0ebd8b3e704f3a82081ef Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 2 Oct 2018 22:03:40 -0700 Subject: [PATCH 1/3] Add support for JNI libraries to android_app modules Make android_app modules a MultiTargets module, which means the common variant will have a list of Targets that it needs to handle. Collect JNI libraries for each Target, and package them into or alongside the APK. Bug: 80095087 Test: app_test.go Change-Id: Iabd3921e1d4c4b4cfcc7e131a0b0d9ab83b0ebbb --- Android.bp | 1 + android/config.go | 4 +- androidmk/cmd/androidmk/android.go | 1 + java/androidmk.go | 4 + java/app.go | 72 +++++++++++++++++- java/app_builder.go | 46 +++++++++++- java/app_test.go | 116 +++++++++++++++++++++++++++++ java/builder.go | 9 +++ java/java.go | 20 ++++- java/java_test.go | 17 ++++- 10 files changed, 276 insertions(+), 14 deletions(-) diff --git a/Android.bp b/Android.bp index aeabb1306..eefa149e9 100644 --- a/Android.bp +++ b/Android.bp @@ -219,6 +219,7 @@ bootstrap_go_package { "blueprint-pathtools", "soong", "soong-android", + "soong-cc", "soong-genrule", "soong-java-config", "soong-tradefed", diff --git a/android/config.go b/android/config.go index 4b10552ab..5da1e0bda 100644 --- a/android/config.go +++ b/android/config.go @@ -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}}, diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go index 1d509805c..0cb6dd68c 100644 --- a/androidmk/cmd/androidmk/android.go +++ b/androidmk/cmd/androidmk/android.go @@ -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", diff --git a/java/androidmk.go b/java/androidmk.go index 313a144e9..7a2fe1e11 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -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) + } }, }, } diff --git a/java/app.go b/java/app.go index dc5296d17..843ced6af 100644 --- a/java/app.go +++ b/java/app.go @@ -19,9 +19,11 @@ package java import ( "strings" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" + "android/soong/cc" "android/soong/tradefed" ) @@ -59,6 +61,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 +77,8 @@ type AndroidApp struct { appProperties appProperties extraLinkFlags []string + + installJniLibs []jniLib } func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths { @@ -92,9 +101,21 @@ 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...) + } } func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -178,7 +199,19 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { packageFile := android.PathForModuleOut(ctx, "package.apk") - CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates) + var jniJarFile android.WritablePath + jniLibs := a.collectJniDeps(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 + } + } + + CreateAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, a.outputFile, certificates) a.outputFile = packageFile @@ -192,6 +225,35 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } } +func (a *AndroidApp) collectJniDeps(ctx android.ModuleContext) []jniLib { + var jniLibs []jniLib + + 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) + + } + } + }) + + return jniLibs +} + func AndroidAppFactory() android.Module { module := &AndroidApp{} @@ -212,7 +274,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 +322,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 +333,7 @@ func AndroidTestFactory() android.Module { &module.appTestProperties, &module.testProperties) - InitJavaModule(module, android.DeviceSupported) + android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) return module } diff --git a/java/app_builder.go b/java/app_builder.go index e27b1b70e..b9b5f43a7 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -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]) +} diff --git a/java/app_test.go b/java/app_test.go index c7c94ece6..f6476dc68 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -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) + } + }) + } +} diff --git a/java/builder.go b/java/builder.go index 07af8ebda..f55a7c796 100644 --- a/java/builder.go +++ b/java/builder.go @@ -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`, diff --git a/java/java.go b/java/java.go index b4b8feb23..7ef3626d6 100644 --- a/java/java.go +++ b/java/java.go @@ -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"} @@ -389,6 +391,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 +605,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 +796,11 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) + if _, ok := tag.(*jniDependencyTag); ok { + // Handled by AndroidApp.collectJniDeps + return + } + if to, ok := module.(*Library); ok { switch tag { case bootClasspathTag, libTag, staticLibTag: diff --git a/java/java_test.go b/java/java_test.go index 82accd5a5..1bfd24bbc 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -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{ From bd01e2abee24a1567438f66602bec4309da85bde Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 4 Oct 2018 15:21:03 -0700 Subject: [PATCH 2/3] Add support for android_app_certificate modules Some android_app modules need certificates located outside their directory. Instead of requiring paths from the root of the tree, add an android_app_certificate module that exports the certificate files. Test: m checkbuild Change-Id: Icbf3898894f3eb857e2d907e3e58dd072c6fabe9 --- androidmk/cmd/androidmk/android.go | 1 + java/app.go | 114 +++++++++++++++++++++-------- java/java.go | 7 +- 3 files changed, 89 insertions(+), 33 deletions(-) diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go index 0cb6dd68c..10e5b0a24 100644 --- a/androidmk/cmd/androidmk/android.go +++ b/androidmk/cmd/androidmk/android.go @@ -155,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, diff --git a/java/app.go b/java/app.go index 843ced6af..b9088c335 100644 --- a/java/app.go +++ b/java/app.go @@ -30,17 +30,18 @@ import ( func init() { android.RegisterModuleType("android_app", AndroidAppFactory) android.RegisterModuleType("android_test", AndroidTestFactory) + 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 @@ -116,6 +117,21 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { } 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) { @@ -171,36 +187,12 @@ 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") + var certificates []certificate + var jniJarFile android.WritablePath - jniLibs := a.collectJniDeps(ctx) + jniLibs, certificateDeps := a.collectAppDeps(ctx) if len(jniLibs) > 0 { embedJni := ctx.Config().UnbundledBuild() || a.appProperties.EmbedJNI if embedJni { @@ -211,6 +203,28 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } } + 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 @@ -225,8 +239,9 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } } -func (a *AndroidApp) collectJniDeps(ctx android.ModuleContext) []jniLib { +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) @@ -248,10 +263,16 @@ func (a *AndroidApp) collectJniDeps(ctx android.ModuleContext) []jniLib { 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 + return jniLibs, certificates } func AndroidAppFactory() android.Module { @@ -337,3 +358,32 @@ func AndroidTestFactory() android.Module { 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"), + } +} diff --git a/java/java.go b/java/java.go index 7ef3626d6..c5414f4fa 100644 --- a/java/java.go +++ b/java/java.go @@ -377,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 { @@ -797,7 +798,11 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { tag := ctx.OtherModuleDependencyTag(module) if _, ok := tag.(*jniDependencyTag); ok { - // Handled by AndroidApp.collectJniDeps + // Handled by AndroidApp.collectAppDeps + return + } + if tag == certificateTag { + // Handled by AndroidApp.collectAppDeps return } From 252fc6f422e2d5328be8f426f7a686f4d9641a49 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Thu, 4 Oct 2018 15:22:03 -0700 Subject: [PATCH 3/3] Add android_test_helper_app Add a module that can build an APK that will be used by a test. The APK will be sideloadable, and can be added to a test suite, but will not autogenerate a test config file. Test: m checkbuild Change-Id: Idf325b1c9a2cbcd16b126da3331671e4aed4b3da --- java/androidmk.go | 15 +++++++++++++++ java/app.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/java/androidmk.go b/java/androidmk.go index 7a2fe1e11..359594c12 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -271,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() diff --git a/java/app.go b/java/app.go index b9088c335..d21b62aec 100644 --- a/java/app.go +++ b/java/app.go @@ -30,6 +30,7 @@ import ( 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) } @@ -359,6 +360,39 @@ func AndroidTestFactory() android.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