Merge "Generate combined deps-info for all updatable modules."
diff --git a/android/config.go b/android/config.go
index ee31c10..59118ce 100644
--- a/android/config.go
+++ b/android/config.go
@@ -897,27 +897,31 @@
}
// Expected format for apexJarValue = <apex name>:<jar name>
-func SplitApexJarPair(apexJarValue string) (string, string) {
- var apexJarPair []string = strings.SplitN(apexJarValue, ":", 2)
- if apexJarPair == nil || len(apexJarPair) != 2 {
- panic(fmt.Errorf("malformed apexJarValue: %q, expected format: <apex>:<jar>",
- apexJarValue))
+func SplitApexJarPair(ctx PathContext, str string) (string, string) {
+ pair := strings.SplitN(str, ":", 2)
+ if len(pair) == 2 {
+ return pair[0], pair[1]
+ } else {
+ reportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
+ return "error-apex", "error-jar"
}
- return apexJarPair[0], apexJarPair[1]
}
-func GetJarsFromApexJarPairs(apexJarPairs []string) []string {
+func GetJarsFromApexJarPairs(ctx PathContext, apexJarPairs []string) []string {
modules := make([]string, len(apexJarPairs))
for i, p := range apexJarPairs {
- _, jar := SplitApexJarPair(p)
+ _, jar := SplitApexJarPair(ctx, p)
modules[i] = jar
}
return modules
}
func (c *config) BootJars() []string {
- return append(GetJarsFromApexJarPairs(c.productVariables.BootJars),
- GetJarsFromApexJarPairs(c.productVariables.UpdatableBootJars)...)
+ ctx := NullPathContext{Config{
+ config: c,
+ }}
+ return append(GetJarsFromApexJarPairs(ctx, c.productVariables.BootJars),
+ GetJarsFromApexJarPairs(ctx, c.productVariables.UpdatableBootJars)...)
}
func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) {
diff --git a/android/module.go b/android/module.go
index 7e64f0a..45477ea 100644
--- a/android/module.go
+++ b/android/module.go
@@ -104,6 +104,8 @@
type BaseModuleContext interface {
EarlyModuleContext
+ blueprintBaseModuleContext() blueprint.BaseModuleContext
+
OtherModuleName(m blueprint.Module) string
OtherModuleDir(m blueprint.Module) string
OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
@@ -1439,6 +1441,10 @@
return b.bp.GetDirectDepWithTag(name, tag)
}
+func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext {
+ return b.bp
+}
+
type moduleContext struct {
bp blueprint.ModuleContext
baseModuleContext
@@ -2361,3 +2367,8 @@
Installed_paths []string `json:"installed,omitempty"`
SrcJars []string `json:"srcjars,omitempty"`
}
+
+func CheckBlueprintSyntax(ctx BaseModuleContext, filename string, contents string) []error {
+ bpctx := ctx.blueprintBaseModuleContext()
+ return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents)
+}
diff --git a/android/paths.go b/android/paths.go
index 8bb9a96..fcea65c 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -43,6 +43,14 @@
var _ PathContext = SingletonContext(nil)
var _ PathContext = ModuleContext(nil)
+// "Null" path context is a minimal path context for a given config.
+type NullPathContext struct {
+ config Config
+}
+
+func (NullPathContext) AddNinjaFileDeps(...string) {}
+func (ctx NullPathContext) Config() Config { return ctx.config }
+
type ModuleInstallPathContext interface {
BaseModuleContext
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 09d3607..6b168fe 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -121,7 +121,7 @@
fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS :=", strings.Join(fi.symlinks, " "))
}
if len(fi.dataPaths) > 0 {
- fmt.Println(w, "LOCAL_TEST_DATA :=", strings.Join(cc.AndroidMkDataPaths(fi.dataPaths), " "))
+ fmt.Fprintln(w, "LOCAL_TEST_DATA :=", strings.Join(cc.AndroidMkDataPaths(fi.dataPaths), " "))
}
if fi.module != nil && len(fi.module.NoticeFiles()) > 0 {
diff --git a/apex/apex.go b/apex/apex.go
index fafa3f8..4fee6e2 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -287,7 +287,10 @@
"android.hidl.token@1.0",
"android.hidl.token@1.0-utils",
"bionic_libc_platform_headers",
+ "exoplayer2-extractor",
+ "exoplayer2-extractor-annotation-stubs",
"gl_headers",
+ "jsr305",
"libEGL",
"libEGL_blobCache",
"libEGL_getProcAddress",
@@ -542,12 +545,6 @@
// Module separator
//
m["com.android.permission"] = []string{
- "androidx.annotation_annotation",
- "androidx.annotation_annotation-nodeps",
- "androidx.lifecycle_lifecycle-common",
- "androidx.lifecycle_lifecycle-common-java8",
- "androidx.lifecycle_lifecycle-common-java8-nodeps",
- "androidx.lifecycle_lifecycle-common-nodeps",
"kotlin-annotations",
"kotlin-stdlib",
"kotlin-stdlib-jdk7",
@@ -618,13 +615,21 @@
// Module separator
//
m["com.android.tethering"] = []string{
- "libnativehelper_compat_libc++",
- "android.hardware.tetheroffload.config@1.0",
+ "android.hardware.tetheroffload.config-V1.0-java",
+ "android.hardware.tetheroffload.control-V1.0-java",
+ "android.hidl.base-V1.0-java",
+ "ipmemorystore-aidl-interfaces-java",
"libcgrouprc",
"libcgrouprc_format",
+ "libnativehelper_compat_libc++",
"libtetherutilsjni",
"libvndksupport",
+ "net-utils-framework-common",
+ "netd_aidl_interface-V3-java",
+ "netlink-client",
+ "networkstack-aidl-interfaces-java",
"tethering-aidl-interfaces-java",
+ "TetheringApiCurrentLib",
}
//
// Module separator
@@ -648,8 +653,6 @@
"android.hidl.manager-V1.0-java",
"android.hidl.manager-V1.1-java",
"android.hidl.manager-V1.2-java",
- "androidx.annotation_annotation",
- "androidx.annotation_annotation-nodeps",
"bouncycastle-unbundled",
"dnsresolver_aidl_interface-V2-java",
"error_prone_annotations",
@@ -671,7 +674,6 @@
"wifi-nano-protos",
"wifi-service-pre-jarjar",
"wifi-service-resources",
- "prebuilt_androidx.annotation_annotation-nodeps",
}
//
// Module separator
@@ -691,6 +693,15 @@
// Module separator
//
m[android.AvailableToAnyApex] = []string{
+ // TODO(b/156996905) Set apex_available/min_sdk_version for androidx/extras support libraries
+ "androidx",
+ "androidx-constraintlayout_constraintlayout",
+ "androidx-constraintlayout_constraintlayout-nodeps",
+ "androidx-constraintlayout_constraintlayout-solver",
+ "androidx-constraintlayout_constraintlayout-solver-nodeps",
+ "com.google.android.material_material",
+ "com.google.android.material_material-nodeps",
+
"libatomic",
"libclang_rt",
"libgcc_stripped",
@@ -710,6 +721,7 @@
android.RegisterModuleType("apex_defaults", defaultsFactory)
android.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
android.RegisterModuleType("override_apex", overrideApexFactory)
+ android.RegisterModuleType("apex_set", apexSetFactory)
android.PreDepsMutators(RegisterPreDepsMutators)
android.PostDepsMutators(RegisterPostDepsMutators)
@@ -1450,19 +1462,7 @@
target,
a.getImageVariation(config))
}
-
- if strings.HasPrefix(ctx.ModuleName(), "com.android.runtime") && target.Os.Class == android.Device {
- for _, sanitizer := range ctx.Config().SanitizeDevice() {
- if sanitizer == "hwaddress" {
- addDependenciesForNativeModules(ctx,
- ApexNativeDependencies{[]string{"libclang_rt.hwasan-aarch64-android"}, nil, nil, nil},
- target, a.getImageVariation(config))
- break
- }
- }
- }
}
-
}
// For prebuilt_etc, use the first variant (64 on 64/32bit device,
@@ -1594,6 +1594,21 @@
return android.InList(sanitizerName, globalSanitizerNames)
}
+func (a *apexBundle) AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string) {
+ if ctx.Device() && sanitizerName == "hwaddress" && strings.HasPrefix(a.Name(), "com.android.runtime") {
+ for _, target := range ctx.MultiTargets() {
+ if target.Arch.ArchType.Multilib == "lib64" {
+ ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+ {Mutator: "image", Variation: a.getImageVariation(ctx.DeviceConfig())},
+ {Mutator: "link", Variation: "shared"},
+ {Mutator: "version", Variation: ""}, // "" is the non-stub variant
+ }...), sharedLibTag, "libclang_rt.hwasan-aarch64-android")
+ break
+ }
+ }
+ }
+}
+
var _ cc.Coverage = (*apexBundle)(nil)
func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
@@ -1853,6 +1868,51 @@
}
}
+// Ensures that a lib providing stub isn't statically linked
+func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) {
+ // Practically, we only care about regular APEXes on the device.
+ if ctx.Host() || a.testApex || a.vndkApex {
+ return
+ }
+
+ a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ if ccm, ok := to.(*cc.Module); ok {
+ apexName := ctx.ModuleName()
+ fromName := ctx.OtherModuleName(from)
+ toName := ctx.OtherModuleName(to)
+
+ // If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither
+ // do any of its dependencies.
+ if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return false
+ }
+
+ // TODO(jiyong) remove this check when R is published to AOSP. Currently, libstatssocket
+ // is capable of providing a stub variant, but is being statically linked from the bluetooth
+ // APEX.
+ if toName == "libstatssocket" {
+ return false
+ }
+
+ // The dynamic linker and crash_dump tool in the runtime APEX is the only exception to this rule.
+ // It can't make the static dependencies dynamic because it can't
+ // do the dynamic linking for itself.
+ if apexName == "com.android.runtime" && (fromName == "linker" || fromName == "crash_dump") {
+ return false
+ }
+
+ isStubLibraryFromOtherApex := ccm.HasStubsVariants() && !android.DirectlyInApex(apexName, toName)
+ if isStubLibraryFromOtherApex && !externalDep {
+ ctx.ModuleErrorf("%q required by %q is a native library providing stub. "+
+ "It shouldn't be included in this APEX via static linking. Dependency path: %s", to.String(), fromName, ctx.GetPathString(false))
+ }
+
+ }
+ return true
+ })
+}
+
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
switch a.properties.ApexType {
@@ -1890,6 +1950,7 @@
a.checkApexAvailability(ctx)
a.checkUpdatable(ctx)
+ a.checkStaticLinkingToStubLibraries(ctx)
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
@@ -2250,6 +2311,10 @@
// We don't want to list them all
moduleName = "libclang_rt"
}
+ if strings.HasPrefix(moduleName, "androidx.") {
+ // TODO(b/156996905) Set apex_available/min_sdk_version for androidx support libraries
+ moduleName = "androidx"
+ }
return moduleName
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 021c3e2..cbe5953 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -175,6 +175,7 @@
"testkey2.pem": nil,
"myapex-arm64.apex": nil,
"myapex-arm.apex": nil,
+ "myapex.apks": nil,
"frameworks/base/api/current.txt": nil,
"framework/aidl/a.aidl": nil,
"build/make/core/proguard.flags": nil,
@@ -218,6 +219,7 @@
ctx.RegisterModuleType("apex_defaults", defaultsFactory)
ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory)
ctx.RegisterModuleType("override_apex", overrideApexFactory)
+ ctx.RegisterModuleType("apex_set", apexSetFactory)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
@@ -907,6 +909,130 @@
}
+func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
+ ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
+ bp := `
+ apex {
+ name: "com.android.runtime",
+ key: "com.android.runtime.key",
+ native_shared_libs: ["libc"],
+ }
+
+ apex_key {
+ name: "com.android.runtime.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libc",
+ no_libcrt: true,
+ nocrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ stubs: { versions: ["1"] },
+ apex_available: ["com.android.runtime"],
+
+ sanitize: {
+ hwaddress: true,
+ }
+ }
+
+ cc_prebuilt_library_shared {
+ name: "libclang_rt.hwasan-aarch64-android",
+ no_libcrt: true,
+ nocrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ srcs: [""],
+ stubs: { versions: ["1"] },
+
+ sanitize: {
+ never: true,
+ },
+ }
+ `
+ // override bp to use hard-coded names: com.android.runtime and libc
+ fs["Android.bp"] = []byte(bp)
+ fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
+ })
+
+ ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
+ "lib64/bionic/libc.so",
+ "lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
+ })
+
+ hwasan := ctx.ModuleForTests("libclang_rt.hwasan-aarch64-android", "android_arm64_armv8-a_shared")
+
+ installed := hwasan.Description("install libclang_rt.hwasan")
+ ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so")
+
+ symlink := hwasan.Description("install symlink libclang_rt.hwasan")
+ ensureEquals(t, symlink.Args["fromPath"], "/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so")
+ ensureContains(t, symlink.Output.String(), "/system/lib64/libclang_rt.hwasan-aarch64-android.so")
+}
+
+func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) {
+ ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
+ bp := `
+ apex {
+ name: "com.android.runtime",
+ key: "com.android.runtime.key",
+ native_shared_libs: ["libc"],
+ }
+
+ apex_key {
+ name: "com.android.runtime.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libc",
+ no_libcrt: true,
+ nocrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ stubs: { versions: ["1"] },
+ apex_available: ["com.android.runtime"],
+ }
+
+ cc_prebuilt_library_shared {
+ name: "libclang_rt.hwasan-aarch64-android",
+ no_libcrt: true,
+ nocrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ srcs: [""],
+ stubs: { versions: ["1"] },
+
+ sanitize: {
+ never: true,
+ },
+ }
+ `
+ // override bp to use hard-coded names: com.android.runtime and libc
+ fs["Android.bp"] = []byte(bp)
+ fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
+
+ config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
+ })
+
+ ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
+ "lib64/bionic/libc.so",
+ "lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
+ })
+
+ hwasan := ctx.ModuleForTests("libclang_rt.hwasan-aarch64-android", "android_arm64_armv8-a_shared")
+
+ installed := hwasan.Description("install libclang_rt.hwasan")
+ ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so")
+
+ symlink := hwasan.Description("install symlink libclang_rt.hwasan")
+ ensureEquals(t, symlink.Args["fromPath"], "/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so")
+ ensureContains(t, symlink.Output.String(), "/system/lib64/libclang_rt.hwasan-aarch64-android.so")
+}
+
func TestApexDependsOnLLNDKTransitively(t *testing.T) {
testcases := []struct {
name string
@@ -4506,10 +4632,78 @@
ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`)
}
-func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
t.Helper()
- bp = bp + `
+ bp := `
+ java_library {
+ name: "some-updatable-apex-lib",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ apex_available: [
+ "some-updatable-apex",
+ ],
+ }
+
+ java_library {
+ name: "some-non-updatable-apex-lib",
+ srcs: ["a.java"],
+ apex_available: [
+ "some-non-updatable-apex",
+ ],
+ }
+
+ java_library {
+ name: "some-platform-lib",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ installable: true,
+ }
+
+ java_library {
+ name: "some-art-lib",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ apex_available: [
+ "com.android.art.something",
+ ],
+ hostdex: true,
+ }
+
+ apex {
+ name: "some-updatable-apex",
+ key: "some-updatable-apex.key",
+ java_libs: ["some-updatable-apex-lib"],
+ updatable: true,
+ min_sdk_version: "current",
+ }
+
+ apex {
+ name: "some-non-updatable-apex",
+ key: "some-non-updatable-apex.key",
+ java_libs: ["some-non-updatable-apex-lib"],
+ }
+
+ apex_key {
+ name: "some-updatable-apex.key",
+ }
+
+ apex_key {
+ name: "some-non-updatable-apex.key",
+ }
+
+ apex {
+ name: "com.android.art.something",
+ key: "com.android.art.something.key",
+ java_libs: ["some-art-lib"],
+ updatable: true,
+ min_sdk_version: "current",
+ }
+
+ apex_key {
+ name: "com.android.art.something.key",
+ }
+
filegroup {
name: "some-updatable-apex-file_contexts",
srcs: [
@@ -4596,145 +4790,86 @@
}
func TestNoUpdatableJarsInBootImage(t *testing.T) {
- bp := `
- java_library {
- name: "some-updatable-apex-lib",
- srcs: ["a.java"],
- sdk_version: "current",
- apex_available: [
- "some-updatable-apex",
- ],
- }
-
- java_library {
- name: "some-non-updatable-apex-lib",
- srcs: ["a.java"],
- apex_available: [
- "some-non-updatable-apex",
- ],
- }
-
- java_library {
- name: "some-platform-lib",
- srcs: ["a.java"],
- sdk_version: "current",
- installable: true,
- }
-
- java_library {
- name: "some-art-lib",
- srcs: ["a.java"],
- sdk_version: "current",
- apex_available: [
- "com.android.art.something",
- ],
- hostdex: true,
- }
-
- apex {
- name: "some-updatable-apex",
- key: "some-updatable-apex.key",
- java_libs: ["some-updatable-apex-lib"],
- updatable: true,
- min_sdk_version: "current",
- }
-
- apex {
- name: "some-non-updatable-apex",
- key: "some-non-updatable-apex.key",
- java_libs: ["some-non-updatable-apex-lib"],
- }
-
- apex_key {
- name: "some-updatable-apex.key",
- }
-
- apex_key {
- name: "some-non-updatable-apex.key",
- }
-
- apex {
- name: "com.android.art.something",
- key: "com.android.art.something.key",
- java_libs: ["some-art-lib"],
- updatable: true,
- min_sdk_version: "current",
- }
-
- apex_key {
- name: "com.android.art.something.key",
- }
- `
var error string
var transform func(*dexpreopt.GlobalConfig)
- // updatable jar from ART apex in the ART boot image => ok
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"com.android.art.something:some-art-lib"}
- }
- testNoUpdatableJarsInBootImage(t, "", bp, transform)
+ t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"com.android.art.something:some-art-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, "", transform)
+ })
- // updatable jar from ART apex in the framework boot image => error
- error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"com.android.art.something:some-art-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
+ error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"com.android.art.something:some-art-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, transform)
+ })
- // updatable jar from some other apex in the ART boot image => error
- error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"some-updatable-apex:some-updatable-apex-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
+ error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"some-updatable-apex:some-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, transform)
+ })
- // non-updatable jar from some other apex in the ART boot image => error
- error = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"some-non-updatable-apex:some-non-updatable-apex-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
+ error = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"some-non-updatable-apex:some-non-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, transform)
+ })
- // updatable jar from some other apex in the framework boot image => error
- error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"some-updatable-apex:some-updatable-apex-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) {
+ error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"some-updatable-apex:some-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, transform)
+ })
- // non-updatable jar from some other apex in the framework boot image => ok
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"some-non-updatable-apex:some-non-updatable-apex-lib"}
- }
- testNoUpdatableJarsInBootImage(t, "", bp, transform)
+ t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"some-non-updatable-apex:some-non-updatable-apex-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, "", transform)
+ })
- // nonexistent jar in the ART boot image => error
- error = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"platform:nonexistent"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
+ error = "failed to find a dex jar path for module 'nonexistent'"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"platform:nonexistent"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, transform)
+ })
- // nonexistent jar in the framework boot image => error
- error = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"platform:nonexistent"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) {
+ error = "failed to find a dex jar path for module 'nonexistent'"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"platform:nonexistent"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, transform)
+ })
- // platform jar in the ART boot image => error
- error = "module 'some-platform-lib' is not allowed in the ART boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"platform:some-platform-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
+ error = "module 'some-platform-lib' is not allowed in the ART boot image"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = []string{"platform:some-platform-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, error, transform)
+ })
- // platform jar in the framework boot image => ok
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"platform:some-platform-lib"}
- }
- testNoUpdatableJarsInBootImage(t, "", bp, transform)
+ t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = []string{"platform:some-platform-lib"}
+ }
+ testNoUpdatableJarsInBootImage(t, "", transform)
+ })
}
func TestTestFor(t *testing.T) {
@@ -4789,6 +4924,84 @@
ensureNotContains(t, ldFlags, "mylib/android_arm64_armv8-a_shared_1/mylib.so")
}
+// TODO(jungjw): Move this to proptools
+func intPtr(i int) *int {
+ return &i
+}
+
+func TestApexSet(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex_set {
+ name: "myapex",
+ set: "myapex.apks",
+ filename: "foo_v2.apex",
+ overrides: ["foo"],
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.Platform_sdk_version = intPtr(30)
+ config.TestProductVariables.DeviceArch = proptools.StringPtr("arm")
+ config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm64")
+ })
+
+ m := ctx.ModuleForTests("myapex", "android_common")
+
+ // Check extract_apks tool parameters.
+ extractedApex := m.Output(buildDir + "/.intermediates/myapex/android_common/foo_v2.apex")
+ actual := extractedApex.Args["abis"]
+ expected := "ARMEABI_V7A,ARM64_V8A"
+ if actual != expected {
+ t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual)
+ }
+ actual = extractedApex.Args["sdk-version"]
+ expected = "30"
+ if actual != expected {
+ t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual)
+ }
+
+ a := m.Module().(*ApexSet)
+ expectedOverrides := []string{"foo"}
+ actualOverrides := android.AndroidMkEntriesForTest(t, config, "", a)[0].EntryMap["LOCAL_OVERRIDES_MODULES"]
+ if !reflect.DeepEqual(actualOverrides, expectedOverrides) {
+ t.Errorf("Incorrect LOCAL_OVERRIDES_MODULES - expected %q vs actual %q", expectedOverrides, actualOverrides)
+ }
+}
+
+func TestNoStaticLinkingToStubsLib(t *testing.T) {
+ testApexError(t, `.*required by "mylib" is a native library providing stub.*`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ static_libs: ["otherlib"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "otherlib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ apex_available: [ "myapex" ],
+ }
+ `)
+}
+
func TestMain(m *testing.M) {
run := func() int {
setUp()
diff --git a/apex/builder.go b/apex/builder.go
index 47ae501..3d0e9b2 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -61,6 +61,7 @@
pctx.HostBinToolVariable("zipalign", "zipalign")
pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest")
+ pctx.HostBinToolVariable("extract_apks", "extract_apks")
}
var (
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index d089c28..03266c5 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -16,13 +16,29 @@
import (
"fmt"
+ "strconv"
"strings"
"android/soong/android"
+ "android/soong/java"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
+var (
+ extractMatchingApex = pctx.StaticRule(
+ "extractMatchingApex",
+ blueprint.RuleParams{
+ Command: `rm -rf "$out" && ` +
+ `${extract_apks} -o "${out}" -allow-prereleased=${allow-prereleased} ` +
+ `-sdk-version=${sdk-version} -abis=${abis} -screen-densities=all -extract-single ` +
+ `${in}`,
+ CommandDeps: []string{"${extract_apks}"},
+ },
+ "abis", "allow-prereleased", "sdk-version")
+)
+
type Prebuilt struct {
android.ModuleBase
prebuilt android.Prebuilt
@@ -208,3 +224,117 @@
},
}}
}
+
+type ApexSet struct {
+ android.ModuleBase
+ prebuilt android.Prebuilt
+
+ properties ApexSetProperties
+
+ installDir android.InstallPath
+ installFilename string
+ outputApex android.WritablePath
+
+ // list of commands to create symlinks for backward compatibility.
+ // these commands will be attached as LOCAL_POST_INSTALL_CMD
+ compatSymlinks []string
+}
+
+type ApexSetProperties struct {
+ // the .apks file path that contains prebuilt apex files to be extracted.
+ Set *string
+
+ // whether the extracted apex file installable.
+ Installable *bool
+
+ // optional name for the installed apex. If unspecified, name of the
+ // module is used as the file name
+ Filename *string
+
+ // names of modules to be overridden. Listed modules can only be other binaries
+ // (in Make or Soong).
+ // This does not completely prevent installation of the overridden binaries, but if both
+ // binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will be removed
+ // from PRODUCT_PACKAGES.
+ Overrides []string
+
+ // apexes in this set use prerelease SDK version
+ Prerelease *bool
+}
+
+func (a *ApexSet) installable() bool {
+ return a.properties.Installable == nil || proptools.Bool(a.properties.Installable)
+}
+
+func (a *ApexSet) InstallFilename() string {
+ return proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+imageApexSuffix)
+}
+
+func (a *ApexSet) Prebuilt() *android.Prebuilt {
+ return &a.prebuilt
+}
+
+func (a *ApexSet) Name() string {
+ return a.prebuilt.Name(a.ModuleBase.Name())
+}
+
+// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
+func apexSetFactory() android.Module {
+ module := &ApexSet{}
+ module.AddProperties(&module.properties)
+ android.InitSingleSourcePrebuiltModule(module, &module.properties, "Set")
+ android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
+func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ a.installFilename = a.InstallFilename()
+ if !strings.HasSuffix(a.installFilename, imageApexSuffix) {
+ ctx.ModuleErrorf("filename should end in %s for apex_set", imageApexSuffix)
+ }
+
+ apexSet := a.prebuilt.SingleSourcePath(ctx)
+ a.outputApex = android.PathForModuleOut(ctx, a.installFilename)
+ ctx.Build(pctx,
+ android.BuildParams{
+ Rule: extractMatchingApex,
+ Description: "Extract an apex from an apex set",
+ Inputs: android.Paths{apexSet},
+ Output: a.outputApex,
+ Args: map[string]string{
+ "abis": strings.Join(java.SupportedAbis(ctx), ","),
+ "allow-prereleased": strconv.FormatBool(proptools.Bool(a.properties.Prerelease)),
+ "sdk-version": ctx.Config().PlatformSdkVersion(),
+ },
+ })
+ a.installDir = android.PathForModuleInstall(ctx, "apex")
+ if a.installable() {
+ ctx.InstallFile(a.installDir, a.installFilename, a.outputApex)
+ }
+
+ // in case that apex_set replaces source apex (using prefer: prop)
+ a.compatSymlinks = makeCompatSymlinks(a.BaseModuleName(), ctx)
+ // or that apex_set overrides other apexes (using overrides: prop)
+ for _, overridden := range a.properties.Overrides {
+ a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
+ }
+}
+
+func (a *ApexSet) AndroidMkEntries() []android.AndroidMkEntries {
+ return []android.AndroidMkEntries{android.AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(a.outputApex),
+ Include: "$(BUILD_PREBUILT)",
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", a.installDir.ToMakePath().String())
+ entries.SetString("LOCAL_MODULE_STEM", a.installFilename)
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !a.installable())
+ entries.AddStrings("LOCAL_OVERRIDES_MODULES", a.properties.Overrides...)
+ if len(a.compatSymlinks) > 0 {
+ entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(a.compatSymlinks, " && "))
+ }
+ },
+ },
+ }}
+}
diff --git a/cc/builder.go b/cc/builder.go
index 41cc0c7..e571e5a 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -99,6 +99,15 @@
},
"arCmd", "arFlags")
+ arWithLibs = pctx.AndroidStaticRule("arWithLibs",
+ blueprint.RuleParams{
+ Command: "rm -f ${out} && $arCmd $arObjFlags $out @${out}.rsp && $arCmd $arLibFlags $out $arLibs",
+ CommandDeps: []string{"$arCmd"},
+ Rspfile: "${out}.rsp",
+ RspfileContent: "${arObjs}",
+ },
+ "arCmd", "arObjFlags", "arObjs", "arLibFlags", "arLibs")
+
darwinStrip = pctx.AndroidStaticRule("darwinStrip",
blueprint.RuleParams{
Command: "${config.MacStripPath} -u -r -o $out $in",
@@ -609,26 +618,45 @@
}
// Generate a rule for compiling multiple .o files to a static library (.a)
-func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
+func TransformObjToStaticLib(ctx android.ModuleContext,
+ objFiles android.Paths, wholeStaticLibs android.Paths,
flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) {
arCmd := "${config.ClangBin}/llvm-ar"
- arFlags := "crsPD"
+ arFlags := ""
if !ctx.Darwin() {
arFlags += " -format=gnu"
}
- ctx.Build(pctx, android.BuildParams{
- Rule: ar,
- Description: "static link " + outputFile.Base(),
- Output: outputFile,
- Inputs: objFiles,
- Implicits: deps,
- Args: map[string]string{
- "arFlags": arFlags,
- "arCmd": arCmd,
- },
- })
+ if len(wholeStaticLibs) == 0 {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: ar,
+ Description: "static link " + outputFile.Base(),
+ Output: outputFile,
+ Inputs: objFiles,
+ Implicits: deps,
+ Args: map[string]string{
+ "arFlags": "crsPD" + arFlags,
+ "arCmd": arCmd,
+ },
+ })
+
+ } else {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: arWithLibs,
+ Description: "static link " + outputFile.Base(),
+ Output: outputFile,
+ Inputs: append(objFiles, wholeStaticLibs...),
+ Implicits: deps,
+ Args: map[string]string{
+ "arCmd": arCmd,
+ "arObjFlags": "crsPD" + arFlags,
+ "arObjs": strings.Join(objFiles.Strings(), " "),
+ "arLibFlags": "cqsL" + arFlags,
+ "arLibs": strings.Join(wholeStaticLibs.Strings(), " "),
+ },
+ })
+ }
}
// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
diff --git a/cc/cc.go b/cc/cc.go
index fbd5bdf..94512d5 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -124,10 +124,16 @@
StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
// Paths to .o files
- Objs Objects
+ Objs Objects
+ // Paths to .o files in dependencies that provide them. Note that these lists
+ // aren't complete since prebuilt modules don't provide the .o files.
StaticLibObjs Objects
WholeStaticLibObjs Objects
+ // Paths to .a files in prebuilts. Complements WholeStaticLibObjs to contain
+ // the libs from all whole_static_lib dependencies.
+ WholeStaticLibsFromPrebuilts android.Paths
+
// Paths to generated source files
GeneratedSources android.Paths
GeneratedHeaders android.Paths
@@ -1068,7 +1074,7 @@
func InstallToBootstrap(name string, config android.Config) bool {
if name == "libclang_rt.hwasan-aarch64-android" {
- return inList("hwaddress", config.SanitizeDevice())
+ return true
}
return isBionic(name)
}
@@ -2482,7 +2488,11 @@
}
ctx.AddMissingDependencies(missingDeps)
}
- depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
+ if _, ok := ccWholeStaticLib.linker.(prebuiltLinkerInterface); ok {
+ depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path())
+ } else {
+ depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
+ }
} else {
ctx.ModuleErrorf(
"non-cc.Modules cannot be included as whole static libraries.", depName)
@@ -2871,6 +2881,9 @@
return false
}
}
+ } else if ctx.OtherModuleDependencyTag(dep) == llndkImplDep {
+ // We don't track beyond LLNDK
+ return false
}
return true
}
diff --git a/cc/coverage.go b/cc/coverage.go
index cc9a1ad..f885fcb 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -92,7 +92,7 @@
// flags that the module may use.
flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
} else if clangCoverage {
- flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-fprofile-instr-generate", "-fcoverage-mapping")
+ flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-fprofile-instr-generate", "-fcoverage-mapping", "-Wno-pass-failed")
}
}
diff --git a/cc/library.go b/cc/library.go
index ecea2ea..47485ce 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -874,7 +874,7 @@
}
}
- TransformObjToStaticLib(ctx, library.objects.objFiles, builderFlags, outputFile, objs.tidyFiles)
+ TransformObjToStaticLib(ctx, library.objects.objFiles, deps.WholeStaticLibsFromPrebuilts, builderFlags, outputFile, objs.tidyFiles)
library.coverageOutputFile = TransformCoverageFilesToZip(ctx, library.objects, ctx.ModuleName())
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 3412c9b..aaaf694 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -989,6 +989,7 @@
android.Module
IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool
EnableSanitizer(sanitizerName string)
+ AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
}
// Create sanitized variants for modules that need them
@@ -1075,6 +1076,7 @@
c.sanitize.Properties.SanitizeDep = false
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) {
// APEX modules fall here
+ sanitizeable.AddSanitizerDependencies(mctx, t.name())
mctx.CreateVariations(t.variationName())
}
}
diff --git a/cc/vndk.go b/cc/vndk.go
index dbe1f3b..e5e4533 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -309,7 +309,13 @@
panic(err)
}
- if m.HasStubsVariants() {
+ if m.HasStubsVariants() && name != "libz" {
+ // b/155456180 libz is the ONLY exception here. We don't want to make
+ // libz an LLNDK library because we in general can't guarantee that
+ // libz will behave consistently especially about the compression.
+ // i.e. the compressed output might be different across releases.
+ // As the library is an external one, it's risky to keep the compatibility
+ // promise if it becomes an LLNDK.
mctx.PropertyErrorf("vndk.enabled", "This library provides stubs. Shouldn't be VNDK. Consider making it as LLNDK")
}
diff --git a/cmd/extract_apks/main.go b/cmd/extract_apks/main.go
index 4a146da..e9a850e 100644
--- a/cmd/extract_apks/main.go
+++ b/cmd/extract_apks/main.go
@@ -21,6 +21,7 @@
"fmt"
"io"
"log"
+ "math"
"os"
"regexp"
"strings"
@@ -32,9 +33,10 @@
)
type TargetConfig struct {
- sdkVersion int32
- screenDpi map[android_bundle_proto.ScreenDensity_DensityAlias]bool
- abis map[android_bundle_proto.Abi_AbiAlias]bool
+ sdkVersion int32
+ screenDpi map[android_bundle_proto.ScreenDensity_DensityAlias]bool
+ // Map holding <ABI alias>:<its sequence number in the flag> info.
+ abis map[android_bundle_proto.Abi_AbiAlias]int
allowPrereleased bool
stem string
}
@@ -88,6 +90,7 @@
}
// Matchers for selection criteria
+
type abiTargetingMatcher struct {
*android_bundle_proto.AbiTargeting
}
@@ -99,12 +102,28 @@
if _, ok := config.abis[android_bundle_proto.Abi_UNSPECIFIED_CPU_ARCHITECTURE]; ok {
return true
}
+ // Find the one that appears first in the abis flags.
+ abiIdx := math.MaxInt32
for _, v := range m.GetValue() {
- if _, ok := config.abis[v.Alias]; ok {
- return true
+ if i, ok := config.abis[v.Alias]; ok {
+ if i < abiIdx {
+ abiIdx = i
+ }
}
}
- return false
+ if abiIdx == math.MaxInt32 {
+ return false
+ }
+ // See if any alternatives appear before the above one.
+ for _, a := range m.GetAlternatives() {
+ if i, ok := config.abis[a.Alias]; ok {
+ if i < abiIdx {
+ // There is a better alternative. Skip this one.
+ return false
+ }
+ }
+ }
+ return true
}
type apkDescriptionMatcher struct {
@@ -161,16 +180,55 @@
userCountriesTargetingMatcher{m.UserCountriesTargeting}.matches(config))
}
+// A higher number means a higher priority.
+// This order must be kept identical to bundletool's.
+var multiAbiPriorities = map[android_bundle_proto.Abi_AbiAlias]int{
+ android_bundle_proto.Abi_ARMEABI: 1,
+ android_bundle_proto.Abi_ARMEABI_V7A: 2,
+ android_bundle_proto.Abi_ARM64_V8A: 3,
+ android_bundle_proto.Abi_X86: 4,
+ android_bundle_proto.Abi_X86_64: 5,
+ android_bundle_proto.Abi_MIPS: 6,
+ android_bundle_proto.Abi_MIPS64: 7,
+}
+
type multiAbiTargetingMatcher struct {
*android_bundle_proto.MultiAbiTargeting
}
-func (t multiAbiTargetingMatcher) matches(_ TargetConfig) bool {
+func (t multiAbiTargetingMatcher) matches(config TargetConfig) bool {
if t.MultiAbiTargeting == nil {
return true
}
- log.Fatal("multiABI based selection is not implemented")
- return false
+ if _, ok := config.abis[android_bundle_proto.Abi_UNSPECIFIED_CPU_ARCHITECTURE]; ok {
+ return true
+ }
+ // Find the one with the highest priority.
+ highestPriority := 0
+ for _, v := range t.GetValue() {
+ for _, a := range v.GetAbi() {
+ if _, ok := config.abis[a.Alias]; ok {
+ if highestPriority < multiAbiPriorities[a.Alias] {
+ highestPriority = multiAbiPriorities[a.Alias]
+ }
+ }
+ }
+ }
+ if highestPriority == 0 {
+ return false
+ }
+ // See if there are any matching alternatives with a higher priority.
+ for _, v := range t.GetAlternatives() {
+ for _, a := range v.GetAbi() {
+ if _, ok := config.abis[a.Alias]; ok {
+ if highestPriority < multiAbiPriorities[a.Alias] {
+ // There's a better one. Skip this one.
+ return false
+ }
+ }
+ }
+ }
+ return true
}
type screenDensityTargetingMatcher struct {
@@ -316,6 +374,10 @@
regexp.MustCompile(`^.*/` + selected.moduleName + `(-.*\.apk)$`),
config.stem + `$1`,
},
+ {
+ regexp.MustCompile(`^universal\.apk$`),
+ config.stem + ".apk",
+ },
}
renamer := func(path string) (string, bool) {
for _, rr := range renameRules {
@@ -349,13 +411,28 @@
return nil
}
+func (apkSet *ApkSet) extractAndCopySingle(selected SelectionResult, outFile *os.File) error {
+ if len(selected.entries) != 1 {
+ return fmt.Errorf("Too many matching entries for extract-single:\n%v", selected.entries)
+ }
+ apk, ok := apkSet.entries[selected.entries[0]]
+ if !ok {
+ return fmt.Errorf("Couldn't find apk path %s", selected.entries[0])
+ }
+ inputReader, _ := apk.Open()
+ _, err := io.Copy(outFile, inputReader)
+ return err
+}
+
// Arguments parsing
var (
- outputZip = flag.String("o", "", "output zip containing extracted entries")
+ outputFile = flag.String("o", "", "output file containing extracted entries")
targetConfig = TargetConfig{
screenDpi: map[android_bundle_proto.ScreenDensity_DensityAlias]bool{},
- abis: map[android_bundle_proto.Abi_AbiAlias]bool{},
+ abis: map[android_bundle_proto.Abi_AbiAlias]int{},
}
+ extractSingle = flag.Bool("extract-single", false,
+ "extract a single target and output it uncompressed. only available for standalone apks and apexes.")
)
// Parse abi values
@@ -368,19 +445,12 @@
}
func (a abiFlagValue) Set(abiList string) error {
- if abiList == "none" {
- return nil
- }
- if abiList == "all" {
- targetConfig.abis[android_bundle_proto.Abi_UNSPECIFIED_CPU_ARCHITECTURE] = true
- return nil
- }
- for _, abi := range strings.Split(abiList, ",") {
+ for i, abi := range strings.Split(abiList, ",") {
v, ok := android_bundle_proto.Abi_AbiAlias_value[abi]
if !ok {
return fmt.Errorf("bad ABI value: %q", abi)
}
- targetConfig.abis[android_bundle_proto.Abi_AbiAlias(v)] = true
+ targetConfig.abis[android_bundle_proto.Abi_AbiAlias(v)] = i
}
return nil
}
@@ -414,20 +484,21 @@
func processArgs() {
flag.Usage = func() {
- fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-zip> -sdk-version value -abis value -screen-densities value <APK set>`)
+ fmt.Fprintln(os.Stderr, `usage: extract_apks -o <output-file> -sdk-version value -abis value `+
+ `-screen-densities value {-stem value | -extract-single} [-allow-prereleased] <APK set>`)
flag.PrintDefaults()
os.Exit(2)
}
version := flag.Uint("sdk-version", 0, "SDK version")
flag.Var(abiFlagValue{&targetConfig}, "abis",
- "'all' or comma-separated ABIs list of ARMEABI ARMEABI_V7A ARM64_V8A X86 X86_64 MIPS MIPS64")
+ "comma-separated ABIs list of ARMEABI ARMEABI_V7A ARM64_V8A X86 X86_64 MIPS MIPS64")
flag.Var(screenDensityFlagValue{&targetConfig}, "screen-densities",
"'all' or comma-separated list of screen density names (NODPI LDPI MDPI TVDPI HDPI XHDPI XXHDPI XXXHDPI)")
flag.BoolVar(&targetConfig.allowPrereleased, "allow-prereleased", false,
"allow prereleased")
- flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name")
+ flag.StringVar(&targetConfig.stem, "stem", "", "output entries base name in the output zip file")
flag.Parse()
- if (*outputZip == "") || len(flag.Args()) != 1 || *version == 0 || targetConfig.stem == "" {
+ if (*outputFile == "") || len(flag.Args()) != 1 || *version == 0 || (targetConfig.stem == "" && !*extractSingle) {
flag.Usage()
}
targetConfig.sdkVersion = int32(*version)
@@ -450,18 +521,24 @@
log.Fatalf("there are no entries for the target configuration: %#v", targetConfig)
}
- outFile, err := os.Create(*outputZip)
+ outFile, err := os.Create(*outputFile)
if err != nil {
log.Fatal(err)
}
defer outFile.Close()
- writer := zip.NewWriter(outFile)
- defer func() {
- if err := writer.Close(); err != nil {
- log.Fatal(err)
- }
- }()
- if err = apkSet.writeApks(sel, targetConfig, writer); err != nil {
+
+ if *extractSingle {
+ err = apkSet.extractAndCopySingle(sel, outFile)
+ } else {
+ writer := zip.NewWriter(outFile)
+ defer func() {
+ if err := writer.Close(); err != nil {
+ log.Fatal(err)
+ }
+ }()
+ err = apkSet.writeApks(sel, targetConfig, writer)
+ }
+ if err != nil {
log.Fatal(err)
}
}
diff --git a/cmd/extract_apks/main_test.go b/cmd/extract_apks/main_test.go
index 1d7726b..bdd4bec 100644
--- a/cmd/extract_apks/main_test.go
+++ b/cmd/extract_apks/main_test.go
@@ -24,31 +24,31 @@
"android/soong/third_party/zip"
)
-type TestConfigDesc struct {
+type testConfigDesc struct {
name string
targetConfig TargetConfig
expected SelectionResult
}
-type TestDesc struct {
+type testDesc struct {
protoText string
- configs []TestConfigDesc
+ configs []testConfigDesc
}
-var (
- testCases = []TestDesc{
+func TestSelectApks_ApkSet(t *testing.T) {
+ testCases := []testDesc{
{
protoText: `
variant {
targeting {
- sdk_version_targeting {
+ sdk_version_targeting {
value { min { value: 29 } } } }
apk_set {
- module_metadata {
+ module_metadata {
name: "base" targeting {} delivery_type: INSTALL_TIME }
apk_description {
targeting {
- screen_density_targeting {
+ screen_density_targeting {
value { density_alias: LDPI } }
sdk_version_targeting {
value { min { value: 21 } } } }
@@ -71,7 +71,10 @@
apk_description {
targeting {
abi_targeting {
- value { alias: ARMEABI_V7A } }
+ value { alias: ARMEABI_V7A }
+ alternatives { alias: ARM64_V8A }
+ alternatives { alias: X86 }
+ alternatives { alias: X86_64 } }
sdk_version_targeting {
value { min { value: 21 } } } }
path: "splits/base-armeabi_v7a.apk"
@@ -79,7 +82,10 @@
apk_description {
targeting {
abi_targeting {
- value { alias: ARM64_V8A } }
+ value { alias: ARM64_V8A }
+ alternatives { alias: ARMEABI_V7A }
+ alternatives { alias: X86 }
+ alternatives { alias: X86_64 } }
sdk_version_targeting {
value { min { value: 21 } } } }
path: "splits/base-arm64_v8a.apk"
@@ -87,7 +93,10 @@
apk_description {
targeting {
abi_targeting {
- value { alias: X86 } }
+ value { alias: X86 }
+ alternatives { alias: ARMEABI_V7A }
+ alternatives { alias: ARM64_V8A }
+ alternatives { alias: X86_64 } }
sdk_version_targeting {
value { min { value: 21 } } } }
path: "splits/base-x86.apk"
@@ -95,7 +104,10 @@
apk_description {
targeting {
abi_targeting {
- value { alias: X86_64 } }
+ value { alias: X86_64 }
+ alternatives { alias: ARMEABI_V7A }
+ alternatives { alias: ARM64_V8A }
+ alternatives { alias: X86 } }
sdk_version_targeting {
value { min { value: 21 } } } }
path: "splits/base-x86_64.apk"
@@ -105,7 +117,7 @@
version: "0.10.3" }
`,
- configs: []TestConfigDesc{
+ configs: []testConfigDesc{
{
name: "one",
targetConfig: TargetConfig{
@@ -113,9 +125,9 @@
screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
},
- abis: map[bp.Abi_AbiAlias]bool{
- bp.Abi_ARMEABI_V7A: true,
- bp.Abi_ARM64_V8A: true,
+ abis: map[bp.Abi_AbiAlias]int{
+ bp.Abi_ARMEABI_V7A: 0,
+ bp.Abi_ARM64_V8A: 1,
},
},
expected: SelectionResult{
@@ -125,7 +137,6 @@
"splits/base-mdpi.apk",
"splits/base-master.apk",
"splits/base-armeabi_v7a.apk",
- "splits/base-arm64_v8a.apk",
},
},
},
@@ -136,7 +147,7 @@
screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
bp.ScreenDensity_LDPI: true,
},
- abis: map[bp.Abi_AbiAlias]bool{},
+ abis: map[bp.Abi_AbiAlias]int{},
},
expected: SelectionResult{
"base",
@@ -153,23 +164,44 @@
screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
bp.ScreenDensity_LDPI: true,
},
- abis: map[bp.Abi_AbiAlias]bool{},
+ abis: map[bp.Abi_AbiAlias]int{},
},
expected: SelectionResult{
"",
nil,
},
},
+ {
+ name: "four",
+ targetConfig: TargetConfig{
+ sdkVersion: 29,
+ screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+ bp.ScreenDensity_MDPI: true,
+ },
+ abis: map[bp.Abi_AbiAlias]int{
+ bp.Abi_ARM64_V8A: 0,
+ bp.Abi_ARMEABI_V7A: 1,
+ },
+ },
+ expected: SelectionResult{
+ "base",
+ []string{
+ "splits/base-mdpi.apk",
+ "splits/base-master.apk",
+ "splits/base-arm64_v8a.apk",
+ },
+ },
+ },
},
},
{
protoText: `
variant {
targeting {
- sdk_version_targeting {
+ sdk_version_targeting {
value { min { value: 10000 } } } }
apk_set {
- module_metadata {
+ module_metadata {
name: "base" targeting {} delivery_type: INSTALL_TIME }
apk_description {
targeting {
@@ -177,13 +209,13 @@
value { min { value: 21 } } } }
path: "splits/base-master.apk"
split_apk_metadata { is_master_split: true } } } }`,
- configs: []TestConfigDesc{
+ configs: []testConfigDesc{
{
name: "Prerelease",
targetConfig: TargetConfig{
sdkVersion: 30,
screenDpi: map[bp.ScreenDensity_DensityAlias]bool{},
- abis: map[bp.Abi_AbiAlias]bool{},
+ abis: map[bp.Abi_AbiAlias]int{},
allowPrereleased: true,
},
expected: SelectionResult{
@@ -193,10 +225,185 @@
},
},
},
+ {
+ protoText: `
+variant {
+ targeting {
+ sdk_version_targeting {
+ value { min { value: 29 } } } }
+ apk_set {
+ module_metadata {
+ name: "base" targeting {} delivery_type: INSTALL_TIME }
+ apk_description {
+ targeting {}
+ path: "universal.apk"
+ standalone_apk_metadata { fused_module_name: "base" } } } }`,
+ configs: []testConfigDesc{
+ {
+ name: "Universal",
+ targetConfig: TargetConfig{sdkVersion: 30},
+ expected: SelectionResult{
+ "base",
+ []string{"universal.apk"},
+ },
+ },
+ },
+ },
}
-)
+ for _, testCase := range testCases {
+ var toc bp.BuildApksResult
+ if err := proto.UnmarshalText(testCase.protoText, &toc); err != nil {
+ t.Fatal(err)
+ }
+ for _, config := range testCase.configs {
+ actual := selectApks(&toc, config.targetConfig)
+ if !reflect.DeepEqual(config.expected, actual) {
+ t.Errorf("%s: expected %v, got %v", config.name, config.expected, actual)
+ }
+ }
+ }
+}
-func TestSelectApks(t *testing.T) {
+func TestSelectApks_ApexSet(t *testing.T) {
+ testCases := []testDesc{
+ {
+ protoText: `
+variant {
+ targeting {
+ sdk_version_targeting {
+ value { min { value: 29 } } } }
+ apk_set {
+ module_metadata {
+ name: "base" targeting {} delivery_type: INSTALL_TIME }
+ apk_description {
+ targeting {
+ multi_abi_targeting {
+ value { abi { alias: ARMEABI_V7A } }
+ alternatives { abi { alias: ARM64_V8A } }
+ alternatives { abi { alias: X86 } }
+ alternatives { abi { alias: X86_64 } } }
+ sdk_version_targeting {
+ value { min { value: 21 } } } }
+ path: "standalones/standalone-armeabi_v7a.apex"
+ apex_apk_metadata { } }
+ apk_description {
+ targeting {
+ multi_abi_targeting {
+ value { abi { alias: ARM64_V8A } }
+ alternatives { abi { alias: ARMEABI_V7A } }
+ alternatives { abi { alias: X86 } }
+ alternatives { abi { alias: X86_64 } } }
+ sdk_version_targeting {
+ value { min { value: 21 } } } }
+ path: "standalones/standalone-arm64_v8a.apex"
+ apex_apk_metadata { } }
+ apk_description {
+ targeting {
+ multi_abi_targeting {
+ value { abi { alias: X86 } }
+ alternatives { abi { alias: ARMEABI_V7A } }
+ alternatives { abi { alias: ARM64_V8A } }
+ alternatives { abi { alias: X86_64 } } }
+ sdk_version_targeting {
+ value { min { value: 21 } } } }
+ path: "standalones/standalone-x86.apex"
+ apex_apk_metadata { } }
+ apk_description {
+ targeting {
+ multi_abi_targeting {
+ value { abi { alias: X86_64 } }
+ alternatives { abi { alias: ARMEABI_V7A } }
+ alternatives { abi { alias: ARM64_V8A } }
+ alternatives { abi { alias: X86 } } }
+ sdk_version_targeting {
+ value { min { value: 21 } } } }
+ path: "standalones/standalone-x86_64.apex"
+ apex_apk_metadata { } } }
+}
+bundletool {
+ version: "0.10.3" }
+
+`,
+ configs: []testConfigDesc{
+ {
+ name: "order matches priorities",
+ targetConfig: TargetConfig{
+ sdkVersion: 29,
+ screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+ bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+ },
+ abis: map[bp.Abi_AbiAlias]int{
+ bp.Abi_ARM64_V8A: 0,
+ bp.Abi_ARMEABI_V7A: 1,
+ },
+ },
+ expected: SelectionResult{
+ "base",
+ []string{
+ "standalones/standalone-arm64_v8a.apex",
+ },
+ },
+ },
+ {
+ name: "order doesn't match priorities",
+ targetConfig: TargetConfig{
+ sdkVersion: 29,
+ screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+ bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+ },
+ abis: map[bp.Abi_AbiAlias]int{
+ bp.Abi_ARMEABI_V7A: 0,
+ bp.Abi_ARM64_V8A: 1,
+ },
+ },
+ expected: SelectionResult{
+ "base",
+ []string{
+ "standalones/standalone-arm64_v8a.apex",
+ },
+ },
+ },
+ {
+ name: "single choice",
+ targetConfig: TargetConfig{
+ sdkVersion: 29,
+ screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+ bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+ },
+ abis: map[bp.Abi_AbiAlias]int{
+ bp.Abi_ARMEABI_V7A: 0,
+ },
+ },
+ expected: SelectionResult{
+ "base",
+ []string{
+ "standalones/standalone-armeabi_v7a.apex",
+ },
+ },
+ },
+ {
+ name: "cross platform",
+ targetConfig: TargetConfig{
+ sdkVersion: 29,
+ screenDpi: map[bp.ScreenDensity_DensityAlias]bool{
+ bp.ScreenDensity_DENSITY_UNSPECIFIED: true,
+ },
+ abis: map[bp.Abi_AbiAlias]int{
+ bp.Abi_ARM64_V8A: 0,
+ bp.Abi_MIPS64: 1,
+ bp.Abi_X86: 2,
+ },
+ },
+ expected: SelectionResult{
+ "base",
+ []string{
+ "standalones/standalone-x86.apex",
+ },
+ },
+ },
+ },
+ },
+ }
for _, testCase := range testCases {
var toc bp.BuildApksResult
if err := proto.UnmarshalText(testCase.protoText, &toc); err != nil {
@@ -223,24 +430,48 @@
return nil
}
-func TestWriteZip(t *testing.T) {
+type testCaseWriteZip struct {
+ name string
+ moduleName string
+ stem string
// what we write from what
- expected := map[string]string{
- "Foo.apk": "splits/mybase-master.apk",
- "Foo-xhdpi.apk": "splits/mybase-xhdpi.apk",
+ expected map[string]string
+}
+
+func TestWriteZip(t *testing.T) {
+ testCases := []testCaseWriteZip{
+ {
+ name: "splits",
+ moduleName: "mybase",
+ stem: "Foo",
+ expected: map[string]string{
+ "Foo.apk": "splits/mybase-master.apk",
+ "Foo-xhdpi.apk": "splits/mybase-xhdpi.apk",
+ },
+ },
+ {
+ name: "universal",
+ moduleName: "base",
+ stem: "Bar",
+ expected: map[string]string{
+ "Bar.apk": "universal.apk",
+ },
+ },
}
- apkSet := ApkSet{entries: make(map[string]*zip.File)}
- sel := SelectionResult{moduleName: "mybase"}
- for _, in := range expected {
- apkSet.entries[in] = &zip.File{FileHeader: zip.FileHeader{Name: in}}
- sel.entries = append(sel.entries, in)
- }
- writer := testZip2ZipWriter{make(map[string]string)}
- config := TargetConfig{stem: "Foo"}
- if err := apkSet.writeApks(sel, config, writer); err != nil {
- t.Error(err)
- }
- if !reflect.DeepEqual(expected, writer.entries) {
- t.Errorf("expected %v, got %v", expected, writer.entries)
+ for _, testCase := range testCases {
+ apkSet := ApkSet{entries: make(map[string]*zip.File)}
+ sel := SelectionResult{moduleName: testCase.moduleName}
+ for _, in := range testCase.expected {
+ apkSet.entries[in] = &zip.File{FileHeader: zip.FileHeader{Name: in}}
+ sel.entries = append(sel.entries, in)
+ }
+ writer := testZip2ZipWriter{make(map[string]string)}
+ config := TargetConfig{stem: testCase.stem}
+ if err := apkSet.writeApks(sel, config, writer); err != nil {
+ t.Error(err)
+ }
+ if !reflect.DeepEqual(testCase.expected, writer.entries) {
+ t.Errorf("expected %v, got %v", testCase.expected, writer.entries)
+ }
}
}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index f1dde9c..fc03563 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -82,7 +82,7 @@
if !dexpreoptDisabled(ctx, global, module) {
// Don't preopt individual boot jars, they will be preopted together.
- if !contains(android.GetJarsFromApexJarPairs(global.BootJars), module.Name) {
+ if !contains(android.GetJarsFromApexJarPairs(ctx, global.BootJars), module.Name) {
appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) &&
!module.NoCreateAppImage
@@ -104,7 +104,7 @@
// Don't preopt system server jars that are updatable.
for _, p := range global.UpdatableSystemServerJars {
- if _, jar := android.SplitApexJarPair(p); jar == module.Name {
+ if _, jar := android.SplitApexJarPair(ctx, p); jar == module.Name {
return true
}
}
@@ -113,7 +113,7 @@
// Also preopt system server jars since selinux prevents system server from loading anything from
// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
// or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options.
- if global.OnlyPreoptBootImageAndSystemServer && !contains(android.GetJarsFromApexJarPairs(global.BootJars), module.Name) &&
+ if global.OnlyPreoptBootImageAndSystemServer && !contains(android.GetJarsFromApexJarPairs(ctx, global.BootJars), module.Name) &&
!contains(global.SystemServerJars, module.Name) && !module.PreoptExtractedApk {
return true
}
@@ -561,8 +561,8 @@
}
// Expected format for apexJarValue = <apex name>:<jar name>
-func GetJarLocationFromApexJarPair(apexJarValue string) string {
- apex, jar := android.SplitApexJarPair(apexJarValue)
+func GetJarLocationFromApexJarPair(ctx android.PathContext, apexJarValue string) string {
+ apex, jar := android.SplitApexJarPair(ctx, apexJarValue)
return filepath.Join("/apex", apex, "javalib", jar+".jar")
}
@@ -573,7 +573,7 @@
func NonUpdatableSystemServerJars(ctx android.PathContext, global *GlobalConfig) []string {
return ctx.Config().Once(nonUpdatableSystemServerJarsKey, func() interface{} {
return android.RemoveListFromList(global.SystemServerJars,
- android.GetJarsFromApexJarPairs(global.UpdatableSystemServerJars))
+ android.GetJarsFromApexJarPairs(ctx, global.UpdatableSystemServerJars))
}).([]string)
}
diff --git a/java/aar.go b/java/aar.go
index 6e3b9e6..c8daf83 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -379,8 +379,11 @@
sharedLibs = append(sharedLibs, exportPackage)
}
- if _, ok := module.(SdkLibraryDependency); ok {
- sdkLibraries = append(sdkLibraries, ctx.OtherModuleName(module))
+ // If the module is (or possibly could be) a component of a java_sdk_library
+ // (including the java_sdk_library) itself then append any implicit sdk library
+ // names to the list of sdk libraries to be added to the manifest.
+ if component, ok := module.(SdkLibraryComponentDependency); ok {
+ sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...)
}
case frameworkResTag:
@@ -513,6 +516,7 @@
module.androidLibraryProperties.BuildAAR = true
+ android.InitApexModule(module)
InitJavaModule(module, android.DeviceSupported)
return module
}
@@ -537,8 +541,12 @@
type AARImport struct {
android.ModuleBase
android.DefaultableModuleBase
+ android.ApexModuleBase
prebuilt android.Prebuilt
+ // Functionality common to Module and Import.
+ embeddableInModuleAndImport
+
properties AARImportProperties
classpathFile android.WritablePath
@@ -742,6 +750,10 @@
return nil, nil
}
+func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ return a.depIsInSameApex(ctx, dep)
+}
+
var _ android.PrebuiltInterface = (*Import)(nil)
// android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
@@ -754,6 +766,7 @@
module.AddProperties(&module.properties)
android.InitPrebuiltModule(module, &module.properties.Aars)
+ android.InitApexModule(module)
InitJavaModule(module, android.DeviceSupported)
return module
}
diff --git a/java/androidmk.go b/java/androidmk.go
index ba1af0d..6747b30 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -211,6 +211,11 @@
}
func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries {
+ if !prebuilt.IsForPlatform() {
+ return []android.AndroidMkEntries{{
+ Disabled: true,
+ }}
+ }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
OutputFile: android.OptionalPathForPath(prebuilt.classpathFile),
@@ -416,6 +421,11 @@
}
func (a *AndroidLibrary) AndroidMkEntries() []android.AndroidMkEntries {
+ if !a.IsForPlatform() {
+ return []android.AndroidMkEntries{{
+ Disabled: true,
+ }}
+ }
entriesList := a.Library.AndroidMkEntries()
entries := &entriesList[0]
diff --git a/java/app.go b/java/app.go
index 37d198e..8241b68 100755
--- a/java/app.go
+++ b/java/app.go
@@ -96,16 +96,16 @@
return Bool(as.properties.Privileged)
}
-var targetCpuAbi = map[string]string{
+var TargetCpuAbi = map[string]string{
"arm": "ARMEABI_V7A",
"arm64": "ARM64_V8A",
"x86": "X86",
"x86_64": "X86_64",
}
-func supportedAbis(ctx android.ModuleContext) []string {
+func SupportedAbis(ctx android.ModuleContext) []string {
abiName := func(archVar string, deviceArch string) string {
- if abi, found := targetCpuAbi[deviceArch]; found {
+ if abi, found := TargetCpuAbi[deviceArch]; found {
return abi
}
ctx.ModuleErrorf("Invalid %s: %s", archVar, deviceArch)
@@ -138,7 +138,7 @@
Output: as.packedOutput,
Inputs: android.Paths{as.prebuilt.SingleSourcePath(ctx)},
Args: map[string]string{
- "abis": strings.Join(supportedAbis(ctx), ","),
+ "abis": strings.Join(SupportedAbis(ctx), ","),
"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
"screen-densities": screenDensities,
"sdk-version": ctx.Config().PlatformSdkVersion(),
@@ -1005,6 +1005,7 @@
}
func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ var configs []tradefed.Config
if a.appTestProperties.Instrumentation_target_package != nil {
a.additionalAaptFlags = append(a.additionalAaptFlags,
"--rename-instrumentation-target-package "+*a.appTestProperties.Instrumentation_target_package)
@@ -1017,8 +1018,12 @@
}
a.generateAndroidBuildActions(ctx)
+ for _, module := range a.testProperties.Test_mainline_modules {
+ configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module})
+ }
+
testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config,
- a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config)
+ a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs)
a.testConfig = a.FixTestConfig(ctx, testConfig)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
}
@@ -1256,6 +1261,8 @@
usesLibrary usesLibrary
+ preprocessed bool
+
installPath android.InstallPath
}
@@ -1271,6 +1278,9 @@
// be set for presigned modules.
Presigned *bool
+ // Name of the signing certificate lineage file.
+ Lineage *string
+
// Sign with the default system dev certificate. Must be used judiciously. Most imported apps
// need to either specify a specific certificate or be presigned.
Default_dev_cert *bool
@@ -1345,7 +1355,7 @@
ctx android.ModuleContext, inputPath android.Path, outputPath android.OutputPath) {
// Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing
// with them may invalidate pre-existing signature data.
- if ctx.InstallInTestcases() && Bool(a.properties.Presigned) {
+ if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || a.preprocessed) {
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
Output: outputPath,
@@ -1366,7 +1376,7 @@
// Returns whether this module should have the dex file stored uncompressed in the APK.
func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool {
- if ctx.Config().UnbundledBuild() {
+ if ctx.Config().UnbundledBuild() || a.preprocessed {
return false
}
@@ -1458,9 +1468,13 @@
apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk")
- // Sign or align the package
// TODO: Handle EXTERNAL
- if !Bool(a.properties.Presigned) {
+
+ // Sign or align the package if package has not been preprocessed
+ if a.preprocessed {
+ a.outputFile = srcApk
+ a.certificate = presignedCertificate
+ } else if !Bool(a.properties.Presigned) {
// If the certificate property is empty at this point, default_dev_cert must be set to true.
// Which makes processMainCert's behavior for the empty cert string WAI.
certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
@@ -1469,7 +1483,11 @@
}
a.certificate = certificates[0]
signed := android.PathForModuleOut(ctx, "signed", apkFilename)
- SignAppPackage(ctx, signed, dexOutput, certificates, nil)
+ var lineageFile android.Path
+ if lineage := String(a.properties.Lineage); lineage != "" {
+ lineageFile = android.PathForModuleSrc(ctx, lineage)
+ }
+ SignAppPackage(ctx, signed, dexOutput, certificates, lineageFile)
a.outputFile = signed
} else {
alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
@@ -1601,15 +1619,24 @@
return module
}
+type androidTestImportProperties struct {
+ // Whether the prebuilt apk can be installed without additional processing. Default is false.
+ Preprocessed *bool
+}
+
type AndroidTestImport struct {
AndroidAppImport
testProperties testProperties
+ testImportProperties androidTestImportProperties
+
data android.Paths
}
func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ a.preprocessed = Bool(a.testImportProperties.Preprocessed)
+
a.generateAndroidBuildActions(ctx)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
@@ -1627,6 +1654,7 @@
module.AddProperties(&module.dexpreoptProperties)
module.AddProperties(&module.usesLibrary.usesLibraryProperties)
module.AddProperties(&module.testProperties)
+ module.AddProperties(&module.testImportProperties)
module.populateAllVariantStructs()
android.AddLoadHook(module, func(ctx android.LoadHookContext) {
module.processVariants(ctx)
diff --git a/java/app_builder.go b/java/app_builder.go
index 1efc856..fb9ab42 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -81,6 +81,7 @@
var flags []string
if lineageFile != nil {
flags = append(flags, "--lineage", lineageFile.String())
+ deps = append(deps, lineageFile)
}
ctx.Build(pctx, android.BuildParams{
diff --git a/java/app_test.go b/java/app_test.go
index 2195afd..1a718f4 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2071,6 +2071,27 @@
}
}
+func TestAndroidAppImport_SigningLineage(t *testing.T) {
+ ctx, _ := testJava(t, `
+ android_app_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ certificate: "platform",
+ lineage: "lineage.bin",
+ }
+ `)
+
+ variant := ctx.ModuleForTests("foo", "android_common")
+
+ // Check cert signing lineage flag.
+ signedApk := variant.Output("signed/foo.apk")
+ signingFlag := signedApk.Args["flags"]
+ expected := "--lineage lineage.bin"
+ if expected != signingFlag {
+ t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag)
+ }
+}
+
func TestAndroidAppImport_DefaultDevCert(t *testing.T) {
ctx, _ := testJava(t, `
android_app_import {
@@ -2348,6 +2369,45 @@
if jniRule != android.Cp.String() {
t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
}
+ if variant.MaybeOutput("zip-aligned/foo_presigned.apk").Rule == nil {
+ t.Errorf("Presigned test apk should be aligned")
+ }
+}
+
+func TestAndroidTestImport_Preprocessed(t *testing.T) {
+ ctx, _ := testJava(t, `
+ android_test_import {
+ name: "foo",
+ apk: "prebuilts/apk/app.apk",
+ presigned: true,
+ preprocessed: true,
+ }
+
+ android_test_import {
+ name: "foo_cert",
+ apk: "prebuilts/apk/app.apk",
+ certificate: "cert/new_cert",
+ preprocessed: true,
+ }
+ `)
+
+ testModules := []string{"foo", "foo_cert"}
+ for _, m := range testModules {
+ apkName := m + ".apk"
+ variant := ctx.ModuleForTests(m, "android_common")
+ jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String()
+ if jniRule != android.Cp.String() {
+ t.Errorf("Unexpected JNI uncompress rule: " + jniRule)
+ }
+
+ // Make sure signing and aligning were skipped.
+ if variant.MaybeOutput("signed/"+apkName).Rule != nil {
+ t.Errorf("signing rule shouldn't be included for preprocessed.")
+ }
+ if variant.MaybeOutput("zip-aligned/"+apkName).Rule != nil {
+ t.Errorf("aligning rule shouldn't be for preprocessed")
+ }
+ }
}
func TestStl(t *testing.T) {
@@ -2423,6 +2483,20 @@
}
java_sdk_library {
+ name: "qux",
+ srcs: ["a.java"],
+ api_packages: ["qux"],
+ sdk_version: "current",
+ }
+
+ java_sdk_library {
+ name: "quuz",
+ srcs: ["a.java"],
+ api_packages: ["quuz"],
+ sdk_version: "current",
+ }
+
+ java_sdk_library {
name: "bar",
srcs: ["a.java"],
api_packages: ["bar"],
@@ -2432,6 +2506,7 @@
android_app {
name: "app",
srcs: ["a.java"],
+ libs: ["qux", "quuz.stubs"],
uses_libs: ["foo"],
sdk_version: "current",
optional_uses_libs: [
@@ -2462,6 +2537,15 @@
app := ctx.ModuleForTests("app", "android_common")
prebuilt := ctx.ModuleForTests("prebuilt", "android_common")
+ // Test that implicit dependencies on java_sdk_library instances are passed to the manifest.
+ manifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
+ if w := "--uses-library qux"; !strings.Contains(manifestFixerArgs, w) {
+ t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
+ }
+ if w := "--uses-library quuz"; !strings.Contains(manifestFixerArgs, w) {
+ t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
+ }
+
// Test that all libraries are verified
cmd := app.Rule("verify_uses_libraries").RuleParams.Command
if w := "--uses-library foo"; !strings.Contains(cmd, w) {
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index dffdc24..90457d0 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -109,11 +109,11 @@
return nil
}
-func (image bootImageConfig) moduleName(idx int) string {
+func (image bootImageConfig) moduleName(ctx android.PathContext, idx int) string {
// Dexpreopt on the boot class path produces multiple files. The first dex file
// is converted into 'name'.art (to match the legacy assumption that 'name'.art
// exists), and the rest are converted to 'name'-<jar>.art.
- _, m := android.SplitApexJarPair(image.modules[idx])
+ _, m := android.SplitApexJarPair(ctx, image.modules[idx])
name := image.stem
if idx != 0 || image.extends != nil {
name += "-" + stemOf(m)
@@ -121,9 +121,9 @@
return name
}
-func (image bootImageConfig) firstModuleNameOrStem() string {
+func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) string {
if len(image.modules) > 0 {
- return image.moduleName(0)
+ return image.moduleName(ctx, 0)
} else {
return image.stem
}
@@ -132,7 +132,7 @@
func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) android.OutputPaths {
ret := make(android.OutputPaths, 0, len(image.modules)*len(exts))
for i := range image.modules {
- name := image.moduleName(i)
+ name := image.moduleName(ctx, i)
for _, ext := range exts {
ret = append(ret, dir.Join(ctx, name+ext))
}
@@ -261,7 +261,7 @@
}
name := ctx.ModuleName(module)
- index := android.IndexList(name, android.GetJarsFromApexJarPairs(image.modules))
+ index := android.IndexList(name, android.GetJarsFromApexJarPairs(ctx, image.modules))
if index == -1 {
return -1, nil
}
@@ -314,7 +314,7 @@
// Ensure all modules were converted to paths
for i := range bootDexJars {
if bootDexJars[i] == nil {
- _, m := android.SplitApexJarPair(image.modules[i])
+ _, m := android.SplitApexJarPair(ctx, image.modules[i])
if ctx.Config().AllowMissingDependencies() {
missingDeps = append(missingDeps, m)
bootDexJars[i] = android.PathForOutput(ctx, "missing")
@@ -614,7 +614,7 @@
return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} {
global := dexpreopt.GetGlobalConfig(ctx)
- updatableModules := android.GetJarsFromApexJarPairs(global.UpdatableBootJars)
+ updatableModules := android.GetJarsFromApexJarPairs(ctx, global.UpdatableBootJars)
// Collect `permitted_packages` for updatable boot jars.
var updatablePackages []string
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 0946bf0..e9704dc 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -24,7 +24,7 @@
"android/soong/dexpreopt"
)
-func TestDexpreoptBootJars(t *testing.T) {
+func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOutputs []string) {
bp := `
java_sdk_library {
name: "foo",
@@ -52,14 +52,39 @@
dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
ctx := testContext()
-
RegisterDexpreoptBootJarsComponents(ctx)
-
run(t, ctx, config)
dexpreoptBootJars := ctx.SingletonForTests("dex_bootjars")
+ rule := dexpreoptBootJars.Output(ruleFile)
- bootArt := dexpreoptBootJars.Output("boot-foo.art")
+ for i := range expectedInputs {
+ expectedInputs[i] = filepath.Join(buildDir, "test_device", expectedInputs[i])
+ }
+
+ for i := range expectedOutputs {
+ expectedOutputs[i] = filepath.Join(buildDir, "test_device", expectedOutputs[i])
+ }
+
+ inputs := rule.Implicits.Strings()
+ sort.Strings(inputs)
+ sort.Strings(expectedInputs)
+
+ outputs := append(android.WritablePaths{rule.Output}, rule.ImplicitOutputs...).Strings()
+ sort.Strings(outputs)
+ sort.Strings(expectedOutputs)
+
+ if !reflect.DeepEqual(inputs, expectedInputs) {
+ t.Errorf("want inputs %q\n got inputs %q", expectedInputs, inputs)
+ }
+
+ if !reflect.DeepEqual(outputs, expectedOutputs) {
+ t.Errorf("want outputs %q\n got outputs %q", expectedOutputs, outputs)
+ }
+}
+
+func TestDexpreoptBootJars(t *testing.T) {
+ ruleFile := "boot-foo.art"
expectedInputs := []string{
"dex_artjars/android/apex/com.android.art/javalib/arm64/boot.art",
@@ -68,47 +93,43 @@
"dex_bootjars_input/baz.jar",
}
- for i := range expectedInputs {
- expectedInputs[i] = filepath.Join(buildDir, "test_device", expectedInputs[i])
- }
-
- inputs := bootArt.Implicits.Strings()
- sort.Strings(inputs)
- sort.Strings(expectedInputs)
-
- if !reflect.DeepEqual(inputs, expectedInputs) {
- t.Errorf("want inputs %q\n got inputs %q", expectedInputs, inputs)
- }
-
expectedOutputs := []string{
"dex_bootjars/android/system/framework/arm64/boot.invocation",
-
"dex_bootjars/android/system/framework/arm64/boot-foo.art",
"dex_bootjars/android/system/framework/arm64/boot-bar.art",
"dex_bootjars/android/system/framework/arm64/boot-baz.art",
-
"dex_bootjars/android/system/framework/arm64/boot-foo.oat",
"dex_bootjars/android/system/framework/arm64/boot-bar.oat",
"dex_bootjars/android/system/framework/arm64/boot-baz.oat",
-
"dex_bootjars/android/system/framework/arm64/boot-foo.vdex",
"dex_bootjars/android/system/framework/arm64/boot-bar.vdex",
"dex_bootjars/android/system/framework/arm64/boot-baz.vdex",
-
"dex_bootjars_unstripped/android/system/framework/arm64/boot-foo.oat",
"dex_bootjars_unstripped/android/system/framework/arm64/boot-bar.oat",
"dex_bootjars_unstripped/android/system/framework/arm64/boot-baz.oat",
}
- for i := range expectedOutputs {
- expectedOutputs[i] = filepath.Join(buildDir, "test_device", expectedOutputs[i])
+ testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs)
+}
+
+// Changes to the boot.zip structure may break the ART APK scanner.
+func TestDexpreoptBootZip(t *testing.T) {
+ ruleFile := "boot.zip"
+
+ ctx := android.PathContextForTesting(testConfig(nil, "", nil))
+ expectedInputs := []string{}
+ for _, target := range dexpreoptTargets(ctx) {
+ for _, ext := range []string{".art", ".oat", ".vdex"} {
+ for _, jar := range []string{"foo", "bar", "baz"} {
+ expectedInputs = append(expectedInputs,
+ filepath.Join("dex_bootjars", target.Os.String(), "system/framework", target.Arch.ArchType.String(), "boot-"+jar+ext))
+ }
+ }
}
- outputs := append(android.WritablePaths{bootArt.Output}, bootArt.ImplicitOutputs...).Strings()
- sort.Strings(outputs)
- sort.Strings(expectedOutputs)
-
- if !reflect.DeepEqual(outputs, expectedOutputs) {
- t.Errorf("want outputs %q\n got outputs %q", expectedOutputs, outputs)
+ expectedOutputs := []string{
+ "dex_bootjars/boot.zip",
}
+
+ testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs)
}
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 41a2ca7..f13d9f2 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -39,7 +39,7 @@
// 2) The jars that are from an updatable apex.
for _, m := range global.UpdatableSystemServerJars {
systemServerClasspathLocations = append(systemServerClasspathLocations,
- dexpreopt.GetJarLocationFromApexJarPair(m))
+ dexpreopt.GetJarLocationFromApexJarPair(ctx, m))
}
if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
@@ -80,7 +80,7 @@
}
func getDexLocation(ctx android.PathContext, target android.Target, module string) string {
- apex, jar := android.SplitApexJarPair(module)
+ apex, jar := android.SplitApexJarPair(ctx, module)
name := stemOf(jar) + ".jar"
@@ -156,7 +156,7 @@
c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
// expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
- imageName := c.firstModuleNameOrStem() + ".art"
+ imageName := c.firstModuleNameOrStem(ctx) + ".art"
// The path to bootclasspath dex files needs to be known at module
// GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
@@ -164,7 +164,7 @@
// TODO(b/143682396): use module dependencies instead
inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
for _, m := range c.modules {
- _, jar := android.SplitApexJarPair(m)
+ _, jar := android.SplitApexJarPair(ctx, m)
c.dexPaths = append(c.dexPaths, inputDir.Join(ctx, stemOf(jar)+".jar"))
}
c.dexPathsDeps = c.dexPaths
@@ -215,7 +215,7 @@
updatableBootclasspath := make([]string, len(global.UpdatableBootJars))
for i, p := range global.UpdatableBootJars {
- updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(p)
+ updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(ctx, p)
}
bootclasspath := append(copyOf(image.getAnyAndroidVariant().dexLocationsDeps), updatableBootclasspath...)
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 414882c..a5a6785 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -351,11 +351,16 @@
ApiFilePath() android.Path
}
+type ApiStubsSrcProvider interface {
+ StubsSrcJar() android.Path
+}
+
// Provider of information about API stubs, used by java_sdk_library.
type ApiStubsProvider interface {
ApiFilePath
RemovedApiFilePath() android.Path
- StubsSrcJar() android.Path
+
+ ApiStubsSrcProvider
}
//
@@ -1932,6 +1937,10 @@
}
}
+func (d *PrebuiltStubsSources) StubsSrcJar() android.Path {
+ return d.stubsSrcJar
+}
+
func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) {
p.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 884a757..ce624bf 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -180,7 +180,9 @@
// b/149353192: when a module is instrumented, jacoco adds synthetic members
// $jacocoData and $jacocoInit. Since they don't exist when building the hidden API flags,
// don't complain when we don't find hidden API flags for the synthetic members.
- if j, ok := ctx.Module().(*Library); ok && j.shouldInstrument(ctx) {
+ if j, ok := ctx.Module().(interface {
+ shouldInstrument(android.BaseModuleContext) bool
+ }); ok && j.shouldInstrument(ctx) {
enforceHiddenApiFlagsToAllMembers = false
}
diff --git a/java/java.go b/java/java.go
index 17b963f..b97defa 100644
--- a/java/java.go
+++ b/java/java.go
@@ -350,6 +350,32 @@
return BoolDefault(me.Optimize.Enabled, me.Optimize.EnabledByDefault)
}
+// Functionality common to Module and Import
+//
+// It is embedded in Module so its functionality can be used by methods in Module
+// but it is currently only initialized by Import and Library.
+type embeddableInModuleAndImport struct {
+
+ // Functionality related to this being used as a component of a java_sdk_library.
+ EmbeddableSdkLibraryComponent
+}
+
+func (e *embeddableInModuleAndImport) initModuleAndImport(moduleBase *android.ModuleBase) {
+ e.initSdkLibraryComponent(moduleBase)
+}
+
+// Module/Import's DepIsInSameApex(...) delegates to this method.
+//
+// This cannot implement DepIsInSameApex(...) directly as that leads to ambiguity with
+// the one provided by ApexModuleBase.
+func (e *embeddableInModuleAndImport) depIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+ // dependencies other than the static linkage are all considered crossing APEX boundary
+ if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
+ return true
+ }
+ return false
+}
+
// Module contains the properties and members used by all java module types
type Module struct {
android.ModuleBase
@@ -357,6 +383,9 @@
android.ApexModuleBase
android.SdkBase
+ // Functionality common to Module and Import.
+ embeddableInModuleAndImport
+
properties CompilerProperties
protoProperties android.ProtoProperties
deviceProperties CompilerDeviceProperties
@@ -473,11 +502,6 @@
JacocoReportClassesFile() android.Path
}
-type SdkLibraryDependency interface {
- SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
- SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
-}
-
type xref interface {
XrefJavaFiles() android.Paths
}
@@ -624,13 +648,15 @@
}
} else if sdkDep.useModule {
ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
- ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
if j.deviceProperties.EffectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
}
}
+ if sdkDep.systemModules != "" {
+ ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
+ }
if ctx.ModuleName() == "android_stubs_current" ||
ctx.ModuleName() == "android_system_stubs_current" ||
@@ -905,6 +931,12 @@
}
}
+ // If this is a component library (stubs, etc.) for a java_sdk_library then
+ // add the name of that java_sdk_library to the exported sdk libs to make sure
+ // that, if necessary, a <uses-library> element for that java_sdk_library is
+ // added to the Android manifest.
+ j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
+
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -924,7 +956,7 @@
case libTag:
deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
// names of sdk libs that are directly depended are exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
+ j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...)
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
@@ -1033,19 +1065,10 @@
}
func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext sdkContext) javaVersion {
- sdk, err := sdkContext.sdkVersion().effectiveVersion(ctx)
- if err != nil {
- ctx.PropertyErrorf("sdk_version", "%s", err)
- }
if javaVersion != "" {
return normalizeJavaVersion(ctx, javaVersion)
- } else if ctx.Device() && sdk <= 23 {
- return JAVA_VERSION_7
- } else if ctx.Device() && sdk <= 29 {
- return JAVA_VERSION_8
- } else if ctx.Device() && ctx.Config().UnbundledBuildUsePrebuiltSdks() {
- // TODO(b/142896162): once we have prebuilt system modules we can use 1.9 for unbundled builds
- return JAVA_VERSION_8
+ } else if ctx.Device() {
+ return sdkContext.sdkVersion().defaultJavaLanguageVersion(ctx)
} else {
return JAVA_VERSION_9
}
@@ -1768,11 +1791,7 @@
}
func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- // Dependencies other than the static linkage are all considered crossing APEX boundary
- if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
- return true
- }
- return false
+ return j.depIsInSameApex(ctx, dep)
}
func (j *Module) Stem() string {
@@ -1978,6 +1997,8 @@
&module.Module.protoProperties,
&module.libraryProperties)
+ module.initModuleAndImport(&module.ModuleBase)
+
android.InitApexModule(module)
android.InitSdkAwareModule(module)
InitJavaModule(module, android.HostAndDeviceSupported)
@@ -2032,6 +2053,10 @@
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
Auto_gen_config *bool
+
+ // Add parameterized mainline modules to auto generated test config. The options will be
+ // handled by TradeFed to do downloading and installing the specified modules on the device.
+ Test_mainline_modules []string
}
type testHelperLibraryProperties struct {
@@ -2386,6 +2411,9 @@
prebuilt android.Prebuilt
android.SdkBase
+ // Functionality common to Module and Import.
+ embeddableInModuleAndImport
+
properties ImportProperties
combinedClasspathFile android.Path
@@ -2443,6 +2471,12 @@
}
j.combinedClasspathFile = outputFile
+ // If this is a component library (impl, stubs, etc.) for a java_sdk_library then
+ // add the name of that java_sdk_library to the exported sdk libs to make sure
+ // that, if necessary, a <uses-library> element for that java_sdk_library is
+ // added to the Android manifest.
+ j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
+
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -2520,11 +2554,7 @@
}
func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- // dependencies other than the static linkage are all considered crossing APEX boundary
- if staticLibTag == ctx.OtherModuleDependencyTag(dep) {
- return true
- }
- return false
+ return j.depIsInSameApex(ctx, dep)
}
// Add compile time check for interface implementation
@@ -2565,6 +2595,8 @@
module.AddProperties(&module.properties)
+ module.initModuleAndImport(&module.ModuleBase)
+
android.InitPrebuiltModule(module, &module.properties.Jars)
android.InitApexModule(module)
android.InitSdkAwareModule(module)
diff --git a/java/java_test.go b/java/java_test.go
index f61f4bb..ab6d88e 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -19,6 +19,7 @@
"os"
"path/filepath"
"reflect"
+ "sort"
"strconv"
"strings"
"testing"
@@ -575,6 +576,7 @@
},
test: {
jars: ["c.jar"],
+ stub_srcs: ["c.java"],
},
}
`)
@@ -1152,13 +1154,42 @@
java_library {
name: "baz",
srcs: ["c.java"],
- libs: ["foo", "bar"],
+ libs: ["foo", "bar.stubs"],
sdk_version: "system_current",
}
+ java_sdk_library {
+ name: "barney",
+ srcs: ["c.java"],
+ api_only: true,
+ }
+ java_sdk_library {
+ name: "betty",
+ srcs: ["c.java"],
+ shared_library: false,
+ }
+ java_sdk_library_import {
+ name: "quuz",
+ public: {
+ jars: ["c.jar"],
+ },
+ }
+ java_sdk_library_import {
+ name: "fred",
+ public: {
+ jars: ["b.jar"],
+ },
+ }
+ java_sdk_library_import {
+ name: "wilma",
+ public: {
+ jars: ["b.jar"],
+ },
+ shared_library: false,
+ }
java_library {
name: "qux",
srcs: ["c.java"],
- libs: ["baz"],
+ libs: ["baz", "fred", "quuz.stubs", "wilma", "barney", "betty"],
sdk_version: "system_current",
}
java_library {
@@ -1223,12 +1254,120 @@
qux := ctx.ModuleForTests("qux", "android_common")
if quxLib, ok := qux.Module().(*Library); ok {
sdkLibs := quxLib.ExportedSdkLibs()
- if len(sdkLibs) != 2 || !android.InList("foo", sdkLibs) || !android.InList("bar", sdkLibs) {
- t.Errorf("qux should export \"foo\" and \"bar\" but exports %v", sdkLibs)
+ sort.Strings(sdkLibs)
+ if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
+ t.Errorf("qux should export %q but exports %q", w, sdkLibs)
}
}
}
+func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
+ testJava(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_packages: ["foo"],
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java", ":foo{.public.stubs.source}"],
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) {
+ testJavaError(t, `"foo" does not provide api scope system`, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_packages: ["foo"],
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java", ":foo{.system.stubs.source}"],
+ }
+ `)
+}
+
+func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
+ testJava(t, `
+ java_sdk_library_import {
+ name: "foo",
+ public: {
+ jars: ["a.jar"],
+ stub_srcs: ["a.java"],
+ current_api: "api/current.txt",
+ removed_api: "api/removed.txt",
+ },
+ }
+
+ java_library {
+ name: "bar",
+ srcs: [":foo{.public.stubs.source}"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
+}
+
+func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) {
+ bp := `
+ java_sdk_library_import {
+ name: "foo",
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `
+
+ t.Run("stubs.source", func(t *testing.T) {
+ testJavaError(t, `stubs.source not available for api scope public`, bp+`
+ java_library {
+ name: "bar",
+ srcs: [":foo{.public.stubs.source}"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
+ })
+
+ t.Run("api.txt", func(t *testing.T) {
+ testJavaError(t, `api.txt not available for api scope public`, bp+`
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ],
+ }
+ `)
+ })
+
+ t.Run("removed-api.txt", func(t *testing.T) {
+ testJavaError(t, `removed-api.txt not available for api scope public`, bp+`
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ java_resources: [
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
+ })
+}
+
func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, `
java_sdk_library {
@@ -1261,6 +1400,45 @@
`)
}
+func TestJavaSdkLibrary_MissingScope(t *testing.T) {
+ testJavaError(t, `requires api scope module-lib from foo but it only has \[\] available`, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ public: {
+ enabled: false,
+ },
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ sdk_version: "module_current",
+ }
+ `)
+}
+
+func TestJavaSdkLibrary_FallbackScope(t *testing.T) {
+ testJava(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ system: {
+ enabled: true,
+ },
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ // foo does not have module-lib scope so it should fallback to system
+ sdk_version: "module_current",
+ }
+ `)
+}
+
var compilerFlagsTestCases = []struct {
in string
out bool
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 03bc76b..999c72f 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -15,11 +15,12 @@
package java
import (
- "android/soong/android"
"sort"
"strings"
"github.com/google/blueprint/proptools"
+
+ "android/soong/android"
)
func init() {
@@ -69,6 +70,10 @@
return
}
+func prebuiltApiModuleName(mctx android.LoadHookContext, module string, scope string, apiver string) string {
+ return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module
+}
+
func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) {
props := struct {
Name *string
@@ -76,7 +81,7 @@
Sdk_version *string
Installable *bool
}{}
- props.Name = proptools.StringPtr(mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module)
+ props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver))
props.Jars = append(props.Jars, path)
// TODO(hansson): change to scope after migration is done.
props.Sdk_version = proptools.StringPtr("current")
@@ -124,6 +129,27 @@
}
}
+func createSystemModules(mctx android.LoadHookContext, apiver string) {
+ props := struct {
+ Name *string
+ Libs []string
+ }{}
+ props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, "system_modules", "public", apiver))
+ props.Libs = append(props.Libs, prebuiltApiModuleName(mctx, "core-for-system-modules", "public", apiver))
+
+ mctx.CreateModule(SystemModulesFactory, &props)
+}
+
+func prebuiltSdkSystemModules(mctx android.LoadHookContext) {
+ for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
+ jar := android.ExistentPathForSource(mctx,
+ mctx.ModuleDir(), apiver, "public", "core-for-system-modules.jar")
+ if jar.Valid() {
+ createSystemModules(mctx, apiver)
+ }
+ }
+}
+
func prebuiltApiFiles(mctx android.LoadHookContext) {
mydir := mctx.ModuleDir() + "/"
// <apiver>/<scope>/api/<module>.txt
@@ -178,6 +204,7 @@
if _, ok := mctx.Module().(*prebuiltApis); ok {
prebuiltApiFiles(mctx)
prebuiltSdkStubs(mctx)
+ prebuiltSdkSystemModules(mctx)
}
}
@@ -191,7 +218,9 @@
// Similarly, it generates a java_import for all API .jar files found under the
// directory where the Android.bp is located. Specifically, an API file located
// at ./<ver>/<scope>/api/<module>.jar generates a java_import module named
-// <prebuilt-api-module>.<scope>.<ver>.<module>.
+// <prebuilt-api-module>_<scope>_<ver>_<module>, and for SDK versions >= 30
+// a java_system_modules module named
+// <prebuilt-api-module>_public_<ver>_system_modules
func PrebuiltApisFactory() android.Module {
module := &prebuiltApis{}
module.AddProperties(&module.properties)
diff --git a/java/sdk.go b/java/sdk.go
index 690451c..9310f78 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -252,6 +252,20 @@
return ver.String(), err
}
+func (s sdkSpec) defaultJavaLanguageVersion(ctx android.EarlyModuleContext) javaVersion {
+ sdk, err := s.effectiveVersion(ctx)
+ if err != nil {
+ ctx.PropertyErrorf("sdk_version", "%s", err)
+ }
+ if sdk <= 23 {
+ return JAVA_VERSION_7
+ } else if sdk <= 29 {
+ return JAVA_VERSION_8
+ } else {
+ return JAVA_VERSION_9
+ }
+}
+
func sdkSpecFrom(str string) sdkSpec {
switch str {
// special cases first
@@ -370,10 +384,16 @@
return sdkDep{}
}
+ var systemModules string
+ if sdkVersion.defaultJavaLanguageVersion(ctx).usesJavaModules() {
+ systemModules = "sdk_public_" + sdkVersion.version.String() + "_system_modules"
+ }
+
return sdkDep{
- useFiles: true,
- jars: android.Paths{jarPath.Path(), lambdaStubsPath},
- aidl: android.OptionalPathForPath(aidlPath.Path()),
+ useFiles: true,
+ jars: android.Paths{jarPath.Path(), lambdaStubsPath},
+ aidl: android.OptionalPathForPath(aidlPath.Path()),
+ systemModules: systemModules,
}
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 7e81c1e..2bdfe0d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -19,6 +19,7 @@
"path"
"path/filepath"
"reflect"
+ "regexp"
"sort"
"strings"
"sync"
@@ -145,6 +146,8 @@
// Initialize a scope, creating and adding appropriate dependency tags
func initApiScope(scope *apiScope) *apiScope {
name := scope.name
+ scopeByName[name] = scope
+ allScopeNames = append(allScopeNames, name)
scope.propertyName = strings.ReplaceAll(name, "-", "_")
scope.fieldName = proptools.FieldNameForProperty(scope.propertyName)
scope.stubsTag = scopeDependencyTag{
@@ -217,6 +220,8 @@
}
var (
+ scopeByName = make(map[string]*apiScope)
+ allScopeNames []string
apiScopePublic = initApiScope(&apiScope{
name: "public",
@@ -367,7 +372,10 @@
// Defaults to "api".
Api_dir *string
- // If set to true there is no runtime library.
+ // Determines whether a runtime implementation library is built; defaults to false.
+ //
+ // If true then it also prevents the module from being used as a shared module, i.e.
+ // it is as is shared_library: false, was set.
Api_only *bool
// local files that are used within user customized droiddoc options.
@@ -433,12 +441,30 @@
//Html_doc *bool
}
+// Paths to outputs from java_sdk_library and java_sdk_library_import.
+//
+// Fields that are android.Paths are always set (during GenerateAndroidBuildActions).
+// OptionalPaths are always set by java_sdk_library but may not be set by
+// java_sdk_library_import as not all instances provide that information.
type scopePaths struct {
- stubsHeaderPath android.Paths
- stubsImplPath android.Paths
- currentApiFilePath android.Path
- removedApiFilePath android.Path
- stubsSrcJar android.Path
+ // The path (represented as Paths for convenience when returning) to the stubs header jar.
+ //
+ // That is the jar that is created by turbine.
+ stubsHeaderPath android.Paths
+
+ // The path (represented as Paths for convenience when returning) to the stubs implementation jar.
+ //
+ // This is not the implementation jar, it still only contains stubs.
+ stubsImplPath android.Paths
+
+ // The API specification file, e.g. system_current.txt.
+ currentApiFilePath android.OptionalPath
+
+ // The specification of API elements removed since the last release.
+ removedApiFilePath android.OptionalPath
+
+ // The stubs source jar.
+ stubsSrcJar android.OptionalPath
}
func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error {
@@ -460,9 +486,18 @@
}
}
+func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider)) error {
+ if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok {
+ action(apiStubsProvider)
+ return nil
+ } else {
+ return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs")
+ }
+}
+
func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider) {
- paths.currentApiFilePath = provider.ApiFilePath()
- paths.removedApiFilePath = provider.RemovedApiFilePath()
+ paths.currentApiFilePath = android.OptionalPathForPath(provider.ApiFilePath())
+ paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath())
}
func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error {
@@ -471,12 +506,12 @@
})
}
-func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsProvider) {
- paths.stubsSrcJar = provider.StubsSrcJar()
+func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider) {
+ paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar())
}
func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error {
- return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
+ return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) {
paths.extractStubsSourceInfoFromApiStubsProviders(provider)
})
}
@@ -500,6 +535,13 @@
//
// TODO(b/155480189) - Remove once naming inconsistencies have been resolved.
Naming_scheme *string
+
+ // Specifies whether this module can be used as an Android shared library; defaults
+ // to true.
+ //
+ // An Android shared library is one that can be referenced in a <uses-library> element
+ // in an AndroidManifest.xml.
+ Shared_library *bool
}
// Common code between sdk library and sdk library import
@@ -510,17 +552,23 @@
namingScheme sdkLibraryComponentNamingScheme
- commonProperties commonToSdkLibraryAndImportProperties
+ commonSdkLibraryProperties commonToSdkLibraryAndImportProperties
+
+ // Functionality related to this being used as a component of a java_sdk_library.
+ EmbeddableSdkLibraryComponent
}
func (c *commonToSdkLibraryAndImport) initCommon(moduleBase *android.ModuleBase) {
c.moduleBase = moduleBase
- moduleBase.AddProperties(&c.commonProperties)
+ moduleBase.AddProperties(&c.commonSdkLibraryProperties)
+
+ // Initialize this as an sdk library component.
+ c.initSdkLibraryComponent(moduleBase)
}
func (c *commonToSdkLibraryAndImport) initCommonAfterDefaultsApplied(ctx android.DefaultableHookContext) bool {
- schemeProperty := proptools.StringDefault(c.commonProperties.Naming_scheme, "default")
+ schemeProperty := proptools.StringDefault(c.commonSdkLibraryProperties.Naming_scheme, "default")
switch schemeProperty {
case "default":
c.namingScheme = &defaultNamingScheme{}
@@ -531,6 +579,12 @@
return false
}
+ // Only track this sdk library if this can be used as a shared library.
+ if c.sharedLibrary() {
+ // Use the name specified in the module definition as the owner.
+ c.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.moduleBase.BaseModuleName())
+ }
+
return true
}
@@ -551,7 +605,83 @@
return c.namingScheme.apiModuleName(apiScope, c.moduleBase.BaseModuleName())
}
-func (c *commonToSdkLibraryAndImport) getScopePaths(scope *apiScope) *scopePaths {
+// The component names for different outputs of the java_sdk_library.
+//
+// They are similar to the names used for the child modules it creates
+const (
+ stubsSourceComponentName = "stubs.source"
+
+ apiTxtComponentName = "api.txt"
+
+ removedApiTxtComponentName = "removed-api.txt"
+)
+
+// A regular expression to match tags that reference a specific stubs component.
+//
+// It will only match if given a valid scope and a valid component. It is verfy strict
+// to ensure it does not accidentally match a similar looking tag that should be processed
+// by the embedded Library.
+var tagSplitter = func() *regexp.Regexp {
+ // Given a list of literal string items returns a regular expression that will
+ // match any one of the items.
+ choice := func(items ...string) string {
+ return `\Q` + strings.Join(items, `\E|\Q`) + `\E`
+ }
+
+ // Regular expression to match one of the scopes.
+ scopesRegexp := choice(allScopeNames...)
+
+ // Regular expression to match one of the components.
+ componentsRegexp := choice(stubsSourceComponentName, apiTxtComponentName, removedApiTxtComponentName)
+
+ // Regular expression to match any combination of one scope and one component.
+ return regexp.MustCompile(fmt.Sprintf(`^\.(%s)\.(%s)$`, scopesRegexp, componentsRegexp))
+}()
+
+// For OutputFileProducer interface
+//
+// .<scope>.stubs.source
+// .<scope>.api.txt
+// .<scope>.removed-api.txt
+func (c *commonToSdkLibraryAndImport) commonOutputFiles(tag string) (android.Paths, error) {
+ if groups := tagSplitter.FindStringSubmatch(tag); groups != nil {
+ scopeName := groups[1]
+ component := groups[2]
+
+ if scope, ok := scopeByName[scopeName]; ok {
+ paths := c.findScopePaths(scope)
+ if paths == nil {
+ return nil, fmt.Errorf("%q does not provide api scope %s", c.moduleBase.BaseModuleName(), scopeName)
+ }
+
+ switch component {
+ case stubsSourceComponentName:
+ if paths.stubsSrcJar.Valid() {
+ return android.Paths{paths.stubsSrcJar.Path()}, nil
+ }
+
+ case apiTxtComponentName:
+ if paths.currentApiFilePath.Valid() {
+ return android.Paths{paths.currentApiFilePath.Path()}, nil
+ }
+
+ case removedApiTxtComponentName:
+ if paths.removedApiFilePath.Valid() {
+ return android.Paths{paths.removedApiFilePath.Path()}, nil
+ }
+ }
+
+ return nil, fmt.Errorf("%s not available for api scope %s", component, scopeName)
+ } else {
+ return nil, fmt.Errorf("unknown scope %s in %s", scope, tag)
+ }
+
+ } else {
+ return nil, nil
+ }
+}
+
+func (c *commonToSdkLibraryAndImport) getScopePathsCreateIfNeeded(scope *apiScope) *scopePaths {
if c.scopePaths == nil {
c.scopePaths = make(map[*apiScope]*scopePaths)
}
@@ -564,6 +694,147 @@
return paths
}
+func (c *commonToSdkLibraryAndImport) findScopePaths(scope *apiScope) *scopePaths {
+ if c.scopePaths == nil {
+ return nil
+ }
+
+ return c.scopePaths[scope]
+}
+
+// If this does not support the requested api scope then find the closest available
+// scope it does support. Returns nil if no such scope is available.
+func (c *commonToSdkLibraryAndImport) findClosestScopePath(scope *apiScope) *scopePaths {
+ for s := scope; s != nil; s = s.extends {
+ if paths := c.findScopePaths(s); paths != nil {
+ return paths
+ }
+ }
+
+ // This should never happen outside tests as public should be the base scope for every
+ // scope and is enabled by default.
+ return nil
+}
+
+func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+
+ // If a specific numeric version has been requested then use prebuilt versions of the sdk.
+ if sdkVersion.version.isNumbered() {
+ return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion)
+ }
+
+ var apiScope *apiScope
+ switch sdkVersion.kind {
+ case sdkSystem:
+ apiScope = apiScopeSystem
+ case sdkModule:
+ apiScope = apiScopeModuleLib
+ case sdkTest:
+ apiScope = apiScopeTest
+ default:
+ apiScope = apiScopePublic
+ }
+
+ paths := c.findClosestScopePath(apiScope)
+ if paths == nil {
+ var scopes []string
+ for _, s := range allApiScopes {
+ if c.findScopePaths(s) != nil {
+ scopes = append(scopes, s.name)
+ }
+ }
+ ctx.ModuleErrorf("requires api scope %s from %s but it only has %q available", apiScope.name, c.moduleBase.BaseModuleName(), scopes)
+ return nil
+ }
+
+ return paths.stubsHeaderPath
+}
+
+func (c *commonToSdkLibraryAndImport) sdkComponentPropertiesForChildLibrary() interface{} {
+ componentProps := &struct {
+ SdkLibraryToImplicitlyTrack *string
+ }{}
+
+ if c.sharedLibrary() {
+ // Mark the stubs library as being components of this java_sdk_library so that
+ // any app that includes code which depends (directly or indirectly) on the stubs
+ // library will have the appropriate <uses-library> invocation inserted into its
+ // manifest if necessary.
+ componentProps.SdkLibraryToImplicitlyTrack = proptools.StringPtr(c.moduleBase.BaseModuleName())
+ }
+
+ return componentProps
+}
+
+// Check if this can be used as a shared library.
+func (c *commonToSdkLibraryAndImport) sharedLibrary() bool {
+ return proptools.BoolDefault(c.commonSdkLibraryProperties.Shared_library, true)
+}
+
+// Properties related to the use of a module as an component of a java_sdk_library.
+type SdkLibraryComponentProperties struct {
+
+ // The name of the java_sdk_library/_import to add to a <uses-library> entry
+ // in the AndroidManifest.xml of any Android app that includes code that references
+ // this module. If not set then no java_sdk_library/_import is tracked.
+ SdkLibraryToImplicitlyTrack *string `blueprint:"mutated"`
+}
+
+// Structure to be embedded in a module struct that needs to support the
+// SdkLibraryComponentDependency interface.
+type EmbeddableSdkLibraryComponent struct {
+ sdkLibraryComponentProperties SdkLibraryComponentProperties
+}
+
+func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(moduleBase *android.ModuleBase) {
+ moduleBase.AddProperties(&e.sdkLibraryComponentProperties)
+}
+
+// to satisfy SdkLibraryComponentDependency
+func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string {
+ if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil {
+ return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack}
+ }
+ return nil
+}
+
+// Implemented by modules that are (or possibly could be) a component of a java_sdk_library
+// (including the java_sdk_library) itself.
+type SdkLibraryComponentDependency interface {
+ // The optional name of the sdk library that should be implicitly added to the
+ // AndroidManifest of an app that contains code which references the sdk library.
+ //
+ // Returns an array containing 0 or 1 items rather than a *string to make it easier
+ // to append this to the list of exported sdk libraries.
+ OptionalImplicitSdkLibrary() []string
+}
+
+// Make sure that all the module types that are components of java_sdk_library/_import
+// and which can be referenced (directly or indirectly) from an android app implement
+// the SdkLibraryComponentDependency interface.
+var _ SdkLibraryComponentDependency = (*Library)(nil)
+var _ SdkLibraryComponentDependency = (*Import)(nil)
+var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
+var _ SdkLibraryComponentDependency = (*sdkLibraryImport)(nil)
+
+// Provides access to sdk_version related header and implentation jars.
+type SdkLibraryDependency interface {
+ SdkLibraryComponentDependency
+
+ // Get the header jars appropriate for the supplied sdk_version.
+ //
+ // These are turbine generated jars so they only change if the externals of the
+ // class changes but it does not contain and implementation or JavaDoc.
+ SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
+
+ // Get the implementation jars appropriate for the supplied sdk version.
+ //
+ // These are either the implementation jar for the whole sdk library or the implementation
+ // jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise
+ // they are identical to the corresponding header jars.
+ SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths
+}
+
type SdkLibrary struct {
Library
@@ -656,17 +927,29 @@
}
}
- if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
- // Add dependency to the rule for generating the xml permissions file
- ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlFileName())
- }
+ if module.requiresRuntimeImplementationLibrary() {
+ if module.sharedLibrary() {
+ // Add dependency to the rule for generating the xml permissions file
+ ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlFileName())
+ }
- module.Library.deps(ctx)
+ // Only add the deps for the library if it is actually going to be built.
+ module.Library.deps(ctx)
+ }
+}
+
+func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) {
+ paths, err := module.commonOutputFiles(tag)
+ if paths == nil && err == nil {
+ return module.Library.OutputFiles(tag)
+ } else {
+ return paths, err
+ }
}
func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // Don't build an implementation library if this is api only.
- if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
+ // Only build an implementation library if required.
+ if module.requiresRuntimeImplementationLibrary() {
module.Library.GenerateAndroidBuildActions(ctx)
}
@@ -679,7 +962,7 @@
// Extract information from any of the scope specific dependencies.
if scopeTag, ok := tag.(scopeDependencyTag); ok {
apiScope := scopeTag.apiScope
- scopePaths := module.getScopePaths(apiScope)
+ scopePaths := module.getScopePathsCreateIfNeeded(apiScope)
// Extract information from the dependency. The exact information extracted
// is determined by the nature of the dependency which is determined by the tag.
@@ -689,7 +972,7 @@
}
func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {
- if proptools.Bool(module.sdkLibraryProperties.Api_only) {
+ if !module.requiresRuntimeImplementationLibrary() {
return nil
}
entriesList := module.Library.AndroidMkEntries()
@@ -747,21 +1030,17 @@
// Creates a static java library that has API stubs
func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
props := struct {
- Name *string
- Visibility []string
- Srcs []string
- Installable *bool
- Sdk_version *string
- System_modules *string
- Patch_module *string
- Libs []string
- Soc_specific *bool
- Device_specific *bool
- Product_specific *bool
- System_ext_specific *bool
- Compile_dex *bool
- Java_version *string
- Product_variables struct {
+ Name *string
+ Visibility []string
+ Srcs []string
+ Installable *bool
+ Sdk_version *string
+ System_modules *string
+ Patch_module *string
+ Libs []string
+ Compile_dex *bool
+ Java_version *string
+ Product_variables struct {
Pdk struct {
Enabled *bool
}
@@ -789,27 +1068,18 @@
props.Srcs = []string{":" + module.stubsSourceModuleName(apiScope)}
sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope)
props.Sdk_version = proptools.StringPtr(sdkVersion)
- props.System_modules = module.Library.Module.deviceProperties.System_modules
- props.Patch_module = module.Library.Module.properties.Patch_module
+ props.System_modules = module.deviceProperties.System_modules
+ props.Patch_module = module.properties.Patch_module
props.Installable = proptools.BoolPtr(false)
props.Libs = module.sdkLibraryProperties.Stub_only_libs
props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
- props.Openjdk9.Srcs = module.Library.Module.properties.Openjdk9.Srcs
- props.Openjdk9.Javacflags = module.Library.Module.properties.Openjdk9.Javacflags
- props.Java_version = module.Library.Module.properties.Java_version
- if module.Library.Module.deviceProperties.Compile_dex != nil {
- props.Compile_dex = module.Library.Module.deviceProperties.Compile_dex
+ props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
+ props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
+ props.Java_version = module.properties.Java_version
+ if module.deviceProperties.Compile_dex != nil {
+ props.Compile_dex = module.deviceProperties.Compile_dex
}
- if module.SocSpecific() {
- props.Soc_specific = proptools.BoolPtr(true)
- } else if module.DeviceSpecific() {
- props.Device_specific = proptools.BoolPtr(true)
- } else if module.ProductSpecific() {
- props.Product_specific = proptools.BoolPtr(true)
- } else if module.SystemExtSpecific() {
- props.System_ext_specific = proptools.BoolPtr(true)
- }
// Dist the class jar artifact for sdk builds.
if !Bool(module.sdkLibraryProperties.No_dist) {
props.Dist.Targets = []string{"sdk", "win_sdk"}
@@ -818,7 +1088,7 @@
props.Dist.Tag = proptools.StringPtr(".jar")
}
- mctx.CreateModule(LibraryFactory, &props)
+ mctx.CreateModule(LibraryFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
// Creates a droidstubs module that creates stubs source files from the given full source
@@ -873,17 +1143,17 @@
visibility := module.sdkLibraryProperties.Stubs_source_visibility
props.Visibility = visibility
- props.Srcs = append(props.Srcs, module.Library.Module.properties.Srcs...)
- props.Sdk_version = module.Library.Module.deviceProperties.Sdk_version
- props.System_modules = module.Library.Module.deviceProperties.System_modules
+ props.Srcs = append(props.Srcs, module.properties.Srcs...)
+ props.Sdk_version = module.deviceProperties.Sdk_version
+ props.System_modules = module.deviceProperties.System_modules
props.Installable = proptools.BoolPtr(false)
// A droiddoc module has only one Libs property and doesn't distinguish between
// shared libs and static libs. So we need to add both of these libs to Libs property.
- props.Libs = module.Library.Module.properties.Libs
- props.Libs = append(props.Libs, module.Library.Module.properties.Static_libs...)
- props.Aidl.Include_dirs = module.Library.Module.deviceProperties.Aidl.Include_dirs
- props.Aidl.Local_include_dirs = module.Library.Module.deviceProperties.Aidl.Local_include_dirs
- props.Java_version = module.Library.Module.properties.Java_version
+ props.Libs = module.properties.Libs
+ props.Libs = append(props.Libs, module.properties.Static_libs...)
+ props.Aidl.Include_dirs = module.deviceProperties.Aidl.Include_dirs
+ props.Aidl.Local_include_dirs = module.deviceProperties.Aidl.Local_include_dirs
+ props.Java_version = module.properties.Java_version
props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
@@ -984,29 +1254,15 @@
// Creates the xml file that publicizes the runtime library
func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) {
props := struct {
- Name *string
- Lib_name *string
- Soc_specific *bool
- Device_specific *bool
- Product_specific *bool
- System_ext_specific *bool
- Apex_available []string
+ Name *string
+ Lib_name *string
+ Apex_available []string
}{
Name: proptools.StringPtr(module.xmlFileName()),
Lib_name: proptools.StringPtr(module.BaseModuleName()),
Apex_available: module.ApexProperties.Apex_available,
}
- if module.SocSpecific() {
- props.Soc_specific = proptools.BoolPtr(true)
- } else if module.DeviceSpecific() {
- props.Device_specific = proptools.BoolPtr(true)
- } else if module.ProductSpecific() {
- props.Product_specific = proptools.BoolPtr(true)
- } else if module.SystemExtSpecific() {
- props.System_ext_specific = proptools.BoolPtr(true)
- }
-
mctx.CreateModule(sdkLibraryXmlFactory, &props)
}
@@ -1037,41 +1293,20 @@
return android.Paths{jarPath.Path()}
}
-func (module *SdkLibrary) sdkJars(
- ctx android.BaseModuleContext,
- sdkVersion sdkSpec,
- headerJars bool) android.Paths {
+func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
- // If a specific numeric version has been requested then use prebuilt versions of the sdk.
- if sdkVersion.version.isNumbered() {
- return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion)
- } else {
- if !sdkVersion.specified() {
- if headerJars {
- return module.Library.HeaderJars()
- } else {
- return module.Library.ImplementationJars()
- }
- }
- var apiScope *apiScope
- switch sdkVersion.kind {
- case sdkSystem:
- apiScope = apiScopeSystem
- case sdkTest:
- apiScope = apiScopeTest
- case sdkPrivate:
- return module.Library.HeaderJars()
- default:
- apiScope = apiScopePublic
- }
-
- paths := module.getScopePaths(apiScope)
+ // Check any special cases for java_sdk_library.
+ if !sdkVersion.specified() {
if headerJars {
- return paths.stubsHeaderPath
+ return module.HeaderJars()
} else {
- return paths.stubsImplPath
+ return module.ImplementationJars()
}
+ } else if sdkVersion.kind == sdkPrivate {
+ return module.HeaderJars()
}
+
+ return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
}
// to satisfy SdkLibraryDependency interface
@@ -1109,7 +1344,7 @@
return
}
- if len(module.Library.Module.properties.Srcs) == 0 {
+ if len(module.properties.Srcs) == 0 {
mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
return
}
@@ -1175,9 +1410,12 @@
module.createStubsLibrary(mctx, scope)
}
- if !proptools.Bool(module.sdkLibraryProperties.Api_only) {
- // for runtime
- module.createXmlFile(mctx)
+ if module.requiresRuntimeImplementationLibrary() {
+ // Only create an XML permissions file that declares the library as being usable
+ // as a shared library if required.
+ if module.sharedLibrary() {
+ module.createXmlFile(mctx)
+ }
// record java_sdk_library modules so that they are exported to make
javaSdkLibraries := javaSdkLibraries(mctx.Config())
@@ -1190,14 +1428,20 @@
func (module *SdkLibrary) InitSdkLibraryProperties() {
module.AddProperties(
&module.sdkLibraryProperties,
- &module.Library.Module.properties,
- &module.Library.Module.dexpreoptProperties,
- &module.Library.Module.deviceProperties,
- &module.Library.Module.protoProperties,
+ &module.properties,
+ &module.dexpreoptProperties,
+ &module.deviceProperties,
+ &module.protoProperties,
)
- module.Library.Module.properties.Installable = proptools.BoolPtr(true)
- module.Library.Module.deviceProperties.IsSDKLibrary = true
+ module.initSdkLibraryComponent(&module.ModuleBase)
+
+ module.properties.Installable = proptools.BoolPtr(true)
+ module.deviceProperties.IsSDKLibrary = true
+}
+
+func (module *SdkLibrary) requiresRuntimeImplementationLibrary() bool {
+ return !proptools.Bool(module.sdkLibraryProperties.Api_only)
}
// Defines how to name the individual component modules the sdk library creates.
@@ -1278,6 +1522,18 @@
android.AddVisibilityProperty(module, "stubs_source_visibility", &module.sdkLibraryProperties.Stubs_source_visibility)
module.SetDefaultableHook(func(ctx android.DefaultableHookContext) {
+ // If no implementation is required then it cannot be used as a shared library
+ // either.
+ if !module.requiresRuntimeImplementationLibrary() {
+ // If shared_library has been explicitly set to true then it is incompatible
+ // with api_only: true.
+ if proptools.Bool(module.commonSdkLibraryProperties.Shared_library) {
+ ctx.PropertyErrorf("api_only/shared_library", "inconsistent settings, shared_library and api_only cannot both be true")
+ }
+ // Set shared_library: false.
+ module.commonSdkLibraryProperties.Shared_library = proptools.BoolPtr(false)
+ }
+
if module.initCommonAfterDefaultsApplied(ctx) {
module.CreateInternalModules(ctx)
}
@@ -1302,10 +1558,10 @@
Stub_srcs []string `android:"path"`
// The current.txt
- Current_api string `android:"path"`
+ Current_api *string `android:"path"`
// The removed.txt
- Removed_api string `android:"path"`
+ Removed_api *string `android:"path"`
}
type sdkLibraryImportProperties struct {
@@ -1415,7 +1671,9 @@
module.createJavaImportForStubs(mctx, apiScope, scopeProperties)
- module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties)
+ if len(scopeProperties.Stub_srcs) > 0 {
+ module.createPrebuiltStubsSources(mctx, apiScope, scopeProperties)
+ }
}
javaSdkLibraries := javaSdkLibraries(mctx.Config())
@@ -1427,15 +1685,11 @@
func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
// Creates a java import for the jar with ".stubs" suffix
props := struct {
- Name *string
- Soc_specific *bool
- Device_specific *bool
- Product_specific *bool
- System_ext_specific *bool
- Sdk_version *string
- Libs []string
- Jars []string
- Prefer *bool
+ Name *string
+ Sdk_version *string
+ Libs []string
+ Jars []string
+ Prefer *bool
}{}
props.Name = proptools.StringPtr(module.stubsLibraryModuleName(apiScope))
props.Sdk_version = scopeProperties.Sdk_version
@@ -1443,18 +1697,11 @@
// scopes to avoid having to duplicate them in each scope.
props.Libs = append(module.properties.Libs, scopeProperties.Libs...)
props.Jars = scopeProperties.Jars
- if module.SocSpecific() {
- props.Soc_specific = proptools.BoolPtr(true)
- } else if module.DeviceSpecific() {
- props.Device_specific = proptools.BoolPtr(true)
- } else if module.ProductSpecific() {
- props.Product_specific = proptools.BoolPtr(true)
- } else if module.SystemExtSpecific() {
- props.System_ext_specific = proptools.BoolPtr(true)
- }
+
// The imports are preferred if the java_sdk_library_import is preferred.
props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
- mctx.CreateModule(ImportFactory, &props)
+
+ mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
}
func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
@@ -1479,45 +1726,48 @@
// Add dependencies to the prebuilt stubs library
ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
+
+ if len(scopeProperties.Stub_srcs) > 0 {
+ // Add dependencies to the prebuilt stubs source library
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
+ }
}
}
+func (module *sdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
+ return module.commonOutputFiles(tag)
+}
+
func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- // Record the paths to the prebuilt stubs library.
+ // Record the paths to the prebuilt stubs library and stubs source.
ctx.VisitDirectDeps(func(to android.Module) {
tag := ctx.OtherModuleDependencyTag(to)
- if lib, ok := to.(Dependency); ok {
- if scopeTag, ok := tag.(scopeDependencyTag); ok {
- apiScope := scopeTag.apiScope
- scopePaths := module.getScopePaths(apiScope)
- scopePaths.stubsHeaderPath = lib.HeaderJars()
- }
+ // Extract information from any of the scope specific dependencies.
+ if scopeTag, ok := tag.(scopeDependencyTag); ok {
+ apiScope := scopeTag.apiScope
+ scopePaths := module.getScopePathsCreateIfNeeded(apiScope)
+
+ // Extract information from the dependency. The exact information extracted
+ // is determined by the nature of the dependency which is determined by the tag.
+ scopeTag.extractDepInfo(ctx, to, scopePaths)
}
})
+
+ // Populate the scope paths with information from the properties.
+ for apiScope, scopeProperties := range module.scopeProperties {
+ if len(scopeProperties.Jars) == 0 {
+ continue
+ }
+
+ paths := module.getScopePathsCreateIfNeeded(apiScope)
+ paths.currentApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Current_api)
+ paths.removedApiFilePath = android.OptionalPathForModuleSrc(ctx, scopeProperties.Removed_api)
+ }
}
-func (module *sdkLibraryImport) sdkJars(
- ctx android.BaseModuleContext,
- sdkVersion sdkSpec) android.Paths {
-
- // If a specific numeric version has been requested then use prebuilt versions of the sdk.
- if sdkVersion.version.isNumbered() {
- return PrebuiltJars(ctx, module.BaseModuleName(), sdkVersion)
- }
-
- var apiScope *apiScope
- switch sdkVersion.kind {
- case sdkSystem:
- apiScope = apiScopeSystem
- case sdkTest:
- apiScope = apiScopeTest
- default:
- apiScope = apiScopePublic
- }
-
- paths := module.getScopePaths(apiScope)
- return paths.stubsHeaderPath
+func (module *sdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+ return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
}
// to satisfy SdkLibraryDependency interface
@@ -1690,21 +1940,25 @@
s.Scopes = make(map[*apiScope]scopeProperties)
for _, apiScope := range allApiScopes {
- paths := sdk.getScopePaths(apiScope)
+ paths := sdk.findScopePaths(apiScope)
+ if paths == nil {
+ continue
+ }
+
jars := paths.stubsImplPath
if len(jars) > 0 {
properties := scopeProperties{}
properties.Jars = jars
properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope)
- properties.StubsSrcJar = paths.stubsSrcJar
- properties.CurrentApiFile = paths.currentApiFilePath
- properties.RemovedApiFile = paths.removedApiFilePath
+ properties.StubsSrcJar = paths.stubsSrcJar.Path()
+ properties.CurrentApiFile = paths.currentApiFilePath.Path()
+ properties.RemovedApiFile = paths.removedApiFilePath.Path()
s.Scopes[apiScope] = properties
}
}
s.Libs = sdk.properties.Libs
- s.Naming_scheme = sdk.commonProperties.Naming_scheme
+ s.Naming_scheme = sdk.commonSdkLibraryProperties.Naming_scheme
}
func (s *sdkLibrarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 088db9e..fb86463 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -83,6 +83,16 @@
},
{
+ name: "sdk v30",
+ properties: `sdk_version: "30",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
+ },
+ {
+
name: "current",
properties: `sdk_version: "current",`,
bootclasspath: []string{"android_stubs_current", "core-lambda-stubs"},
@@ -110,6 +120,16 @@
},
{
+ name: "system_30",
+ properties: `sdk_version: "system_30",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/system/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
+ },
+ {
+
name: "test_current",
properties: `sdk_version: "test_current",`,
bootclasspath: []string{"android_test_stubs_current", "core-lambda-stubs"},
@@ -176,12 +196,24 @@
},
{
+ name: "unbundled sdk v30",
+ unbundled: true,
+ properties: `sdk_version: "30",`,
+ bootclasspath: []string{`""`},
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
+ },
+ {
+
name: "unbundled current",
unbundled: true,
properties: `sdk_version: "current",`,
bootclasspath: []string{`""`},
- forces8: true,
+ system: "sdk_public_current_system_modules",
java8classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/current/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
aidl: "-pprebuilts/sdk/current/public/framework.aidl",
},
@@ -189,27 +221,30 @@
name: "pdk default",
pdk: true,
bootclasspath: []string{`""`},
- forces8: true,
- java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- aidl: "-pprebuilts/sdk/29/public/framework.aidl",
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
},
{
name: "pdk current",
pdk: true,
properties: `sdk_version: "current",`,
bootclasspath: []string{`""`},
- forces8: true,
- java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- aidl: "-pprebuilts/sdk/29/public/framework.aidl",
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
},
{
name: "pdk 29",
pdk: true,
properties: `sdk_version: "29",`,
bootclasspath: []string{`""`},
- forces8: true,
- java8classpath: []string{"prebuilts/sdk/29/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- aidl: "-pprebuilts/sdk/29/public/framework.aidl",
+ system: "sdk_public_30_system_modules",
+ java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
+ aidl: "-pprebuilts/sdk/30/public/framework.aidl",
},
{
name: "module_current",
@@ -292,12 +327,16 @@
if testcase.system == "none" {
system = "--system=none"
} else if testcase.system != "" {
- system = "--system=" + filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system")
+ dir := ""
+ if strings.HasPrefix(testcase.system, "sdk_public_") {
+ dir = "prebuilts/sdk"
+ }
+ system = "--system=" + filepath.Join(buildDir, ".intermediates", dir, testcase.system, "android_common", "system")
// The module-relative parts of these paths are hardcoded in system_modules.go:
systemDeps = []string{
- filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system", "lib", "modules"),
- filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system", "lib", "jrt-fs.jar"),
- filepath.Join(buildDir, ".intermediates", testcase.system, "android_common", "system", "release"),
+ filepath.Join(buildDir, ".intermediates", dir, testcase.system, "android_common", "system", "lib", "modules"),
+ filepath.Join(buildDir, ".intermediates", dir, testcase.system, "android_common", "system", "lib", "jrt-fs.jar"),
+ filepath.Join(buildDir, ".intermediates", dir, testcase.system, "android_common", "system", "release"),
}
}
diff --git a/java/testing.go b/java/testing.go
index 53181a0..1967148 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -55,36 +55,54 @@
"assets_a/a": nil,
"assets_b/b": nil,
- "prebuilts/sdk/14/public/android.jar": nil,
- "prebuilts/sdk/14/public/framework.aidl": nil,
- "prebuilts/sdk/14/system/android.jar": nil,
- "prebuilts/sdk/17/public/android.jar": nil,
- "prebuilts/sdk/17/public/framework.aidl": nil,
- "prebuilts/sdk/17/system/android.jar": nil,
- "prebuilts/sdk/29/public/android.jar": nil,
- "prebuilts/sdk/29/public/framework.aidl": nil,
- "prebuilts/sdk/29/system/android.jar": nil,
- "prebuilts/sdk/29/system/foo.jar": nil,
- "prebuilts/sdk/current/core/android.jar": nil,
- "prebuilts/sdk/current/public/android.jar": nil,
- "prebuilts/sdk/current/public/framework.aidl": nil,
- "prebuilts/sdk/current/public/core.jar": nil,
- "prebuilts/sdk/current/system/android.jar": nil,
- "prebuilts/sdk/current/test/android.jar": nil,
- "prebuilts/sdk/28/public/api/foo.txt": nil,
- "prebuilts/sdk/28/system/api/foo.txt": nil,
- "prebuilts/sdk/28/test/api/foo.txt": nil,
- "prebuilts/sdk/28/public/api/foo-removed.txt": nil,
- "prebuilts/sdk/28/system/api/foo-removed.txt": nil,
- "prebuilts/sdk/28/test/api/foo-removed.txt": nil,
- "prebuilts/sdk/28/public/api/bar.txt": nil,
- "prebuilts/sdk/28/system/api/bar.txt": nil,
- "prebuilts/sdk/28/test/api/bar.txt": nil,
- "prebuilts/sdk/28/public/api/bar-removed.txt": nil,
- "prebuilts/sdk/28/system/api/bar-removed.txt": nil,
- "prebuilts/sdk/28/test/api/bar-removed.txt": nil,
- "prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
- "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "current"],}`),
+ "prebuilts/sdk/14/public/android.jar": nil,
+ "prebuilts/sdk/14/public/framework.aidl": nil,
+ "prebuilts/sdk/14/system/android.jar": nil,
+ "prebuilts/sdk/17/public/android.jar": nil,
+ "prebuilts/sdk/17/public/framework.aidl": nil,
+ "prebuilts/sdk/17/system/android.jar": nil,
+ "prebuilts/sdk/29/public/android.jar": nil,
+ "prebuilts/sdk/29/public/framework.aidl": nil,
+ "prebuilts/sdk/29/system/android.jar": nil,
+ "prebuilts/sdk/29/system/foo.jar": nil,
+ "prebuilts/sdk/30/public/android.jar": nil,
+ "prebuilts/sdk/30/public/framework.aidl": nil,
+ "prebuilts/sdk/30/system/android.jar": nil,
+ "prebuilts/sdk/30/system/foo.jar": nil,
+ "prebuilts/sdk/30/public/core-for-system-modules.jar": nil,
+ "prebuilts/sdk/current/core/android.jar": nil,
+ "prebuilts/sdk/current/public/android.jar": nil,
+ "prebuilts/sdk/current/public/framework.aidl": nil,
+ "prebuilts/sdk/current/public/core.jar": nil,
+ "prebuilts/sdk/current/public/core-for-system-modules.jar": nil,
+ "prebuilts/sdk/current/system/android.jar": nil,
+ "prebuilts/sdk/current/test/android.jar": nil,
+ "prebuilts/sdk/28/public/api/foo.txt": nil,
+ "prebuilts/sdk/28/system/api/foo.txt": nil,
+ "prebuilts/sdk/28/test/api/foo.txt": nil,
+ "prebuilts/sdk/28/public/api/foo-removed.txt": nil,
+ "prebuilts/sdk/28/system/api/foo-removed.txt": nil,
+ "prebuilts/sdk/28/test/api/foo-removed.txt": nil,
+ "prebuilts/sdk/28/public/api/bar.txt": nil,
+ "prebuilts/sdk/28/system/api/bar.txt": nil,
+ "prebuilts/sdk/28/test/api/bar.txt": nil,
+ "prebuilts/sdk/28/public/api/bar-removed.txt": nil,
+ "prebuilts/sdk/28/system/api/bar-removed.txt": nil,
+ "prebuilts/sdk/28/test/api/bar-removed.txt": nil,
+ "prebuilts/sdk/30/public/api/foo.txt": nil,
+ "prebuilts/sdk/30/system/api/foo.txt": nil,
+ "prebuilts/sdk/30/test/api/foo.txt": nil,
+ "prebuilts/sdk/30/public/api/foo-removed.txt": nil,
+ "prebuilts/sdk/30/system/api/foo-removed.txt": nil,
+ "prebuilts/sdk/30/test/api/foo-removed.txt": nil,
+ "prebuilts/sdk/30/public/api/bar.txt": nil,
+ "prebuilts/sdk/30/system/api/bar.txt": nil,
+ "prebuilts/sdk/30/test/api/bar.txt": nil,
+ "prebuilts/sdk/30/public/api/bar-removed.txt": nil,
+ "prebuilts/sdk/30/system/api/bar-removed.txt": nil,
+ "prebuilts/sdk/30/test/api/bar-removed.txt": nil,
+ "prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
+ "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`),
"prebuilts/apk/app.apk": nil,
"prebuilts/apk/app_arm.apk": nil,
diff --git a/sdk/update.go b/sdk/update.go
index 476a4a5..1ba5806 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -350,6 +350,9 @@
bp = newGeneratedFile(ctx, "snapshot", "Android.bp")
generateBpContents(&bp.generatedContents, bpFile)
+ contents := bp.content.String()
+ syntaxCheckSnapshotBpFile(ctx, contents)
+
bp.build(pctx, ctx, nil)
filesToZip := builder.filesToZip
@@ -394,6 +397,36 @@
return outputZipFile
}
+// Check the syntax of the generated Android.bp file contents and if they are
+// invalid then log an error with the contents (tagged with line numbers) and the
+// errors that were found so that it is easy to see where the problem lies.
+func syntaxCheckSnapshotBpFile(ctx android.ModuleContext, contents string) {
+ errs := android.CheckBlueprintSyntax(ctx, "Android.bp", contents)
+ if len(errs) != 0 {
+ message := &strings.Builder{}
+ _, _ = fmt.Fprint(message, `errors in generated Android.bp snapshot:
+
+Generated Android.bp contents
+========================================================================
+`)
+ for i, line := range strings.Split(contents, "\n") {
+ _, _ = fmt.Fprintf(message, "%6d: %s\n", i+1, line)
+ }
+
+ _, _ = fmt.Fprint(message, `
+========================================================================
+
+Errors found:
+`)
+
+ for _, err := range errs {
+ _, _ = fmt.Fprintf(message, "%s\n", err.Error())
+ }
+
+ ctx.ModuleErrorf("%s", message.String())
+ }
+}
+
func extractCommonProperties(ctx android.ModuleContext, extractor *commonValueExtractor, commonProperties interface{}, inputPropertiesSlice interface{}) {
err := extractor.extractCommonProperties(commonProperties, inputPropertiesSlice)
if err != nil {
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 596284b..be44cac 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -219,31 +219,39 @@
}
var autogenInstrumentationTest = pctx.StaticRule("autogenInstrumentationTest", blueprint.RuleParams{
- Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template",
+ Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template ${extraConfigs}",
CommandDeps: []string{
"${AutoGenTestConfigScript}",
"${EmptyTestConfig}",
"$template",
},
-}, "name", "template")
+}, "name", "template", "extraConfigs")
func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool) android.Path {
+ testConfigTemplateProp *string, manifest android.Path, testSuites []string, autoGenConfig *bool, configs []Config) android.Path {
path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
+ var configStrings []string
if autogenPath != nil {
template := "${InstrumentationTestConfigTemplate}"
moduleTemplate := getTestConfigTemplate(ctx, testConfigTemplateProp)
if moduleTemplate.Valid() {
template = moduleTemplate.String()
}
+ for _, config := range configs {
+ configStrings = append(configStrings, config.Config())
+ }
+ extraConfigs := strings.Join(configStrings, fmt.Sprintf("\\n%s", test_xml_indent))
+ extraConfigs = fmt.Sprintf("--extra-configs '%s'", extraConfigs)
+
ctx.Build(pctx, android.BuildParams{
Rule: autogenInstrumentationTest,
Description: "test config",
Input: manifest,
Output: autogenPath,
Args: map[string]string{
- "name": ctx.ModuleName(),
- "template": template,
+ "name": ctx.ModuleName(),
+ "template": template,
+ "extraConfigs": extraConfigs,
},
})
return autogenPath
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index 1b13e5d..fa44cb1 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -39,6 +39,7 @@
args := []string{
"-d", "keepdepfile",
"-d", "keeprsp",
+ "-d", "stats",
"--frontend_file", fifo,
}
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 2fbf381..6a12add 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -119,6 +119,7 @@
cmd := Command(ctx, config, "soong "+name,
config.PrebuiltBuildTool("ninja"),
"-d", "keepdepfile",
+ "-d", "stats",
"-o", "usesphonyoutputs=yes",
"-o", "preremoveoutputs=yes",
"-w", "dupbuild=err",
diff --git a/ui/status/ninja.go b/ui/status/ninja.go
index 9cf2f6a..a11774c 100644
--- a/ui/status/ninja.go
+++ b/ui/status/ninja.go
@@ -174,6 +174,8 @@
n.status.Print("warning: " + message)
case ninja_frontend.Status_Message_ERROR:
n.status.Error(message)
+ case ninja_frontend.Status_Message_DEBUG:
+ n.status.Verbose(message)
default:
n.status.Print(message)
}
diff --git a/ui/status/ninja_frontend/frontend.pb.go b/ui/status/ninja_frontend/frontend.pb.go
index 7c05eed..7ba9de2 100644
--- a/ui/status/ninja_frontend/frontend.pb.go
+++ b/ui/status/ninja_frontend/frontend.pb.go
@@ -3,9 +3,11 @@
package ninja_frontend
-import proto "github.com/golang/protobuf/proto"
-import fmt "fmt"
-import math "math"
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@@ -16,7 +18,7 @@
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Status_Message_Level int32
@@ -24,17 +26,21 @@
Status_Message_INFO Status_Message_Level = 0
Status_Message_WARNING Status_Message_Level = 1
Status_Message_ERROR Status_Message_Level = 2
+ Status_Message_DEBUG Status_Message_Level = 3
)
var Status_Message_Level_name = map[int32]string{
0: "INFO",
1: "WARNING",
2: "ERROR",
+ 3: "DEBUG",
}
+
var Status_Message_Level_value = map[string]int32{
"INFO": 0,
"WARNING": 1,
"ERROR": 2,
+ "DEBUG": 3,
}
func (x Status_Message_Level) Enum() *Status_Message_Level {
@@ -42,9 +48,11 @@
*p = x
return p
}
+
func (x Status_Message_Level) String() string {
return proto.EnumName(Status_Message_Level_name, int32(x))
}
+
func (x *Status_Message_Level) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(Status_Message_Level_value, data, "Status_Message_Level")
if err != nil {
@@ -53,8 +61,9 @@
*x = Status_Message_Level(value)
return nil
}
+
func (Status_Message_Level) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 5, 0}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 5, 0}
}
type Status struct {
@@ -73,16 +82,17 @@
func (m *Status) String() string { return proto.CompactTextString(m) }
func (*Status) ProtoMessage() {}
func (*Status) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0}
+ return fileDescriptor_eca3873955a29cfe, []int{0}
}
+
func (m *Status) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status.Unmarshal(m, b)
}
func (m *Status) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status.Marshal(b, m, deterministic)
}
-func (dst *Status) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status.Merge(dst, src)
+func (m *Status) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status.Merge(m, src)
}
func (m *Status) XXX_Size() int {
return xxx_messageInfo_Status.Size(m)
@@ -147,16 +157,17 @@
func (m *Status_TotalEdges) String() string { return proto.CompactTextString(m) }
func (*Status_TotalEdges) ProtoMessage() {}
func (*Status_TotalEdges) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 0}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 0}
}
+
func (m *Status_TotalEdges) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_TotalEdges.Unmarshal(m, b)
}
func (m *Status_TotalEdges) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_TotalEdges.Marshal(b, m, deterministic)
}
-func (dst *Status_TotalEdges) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_TotalEdges.Merge(dst, src)
+func (m *Status_TotalEdges) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_TotalEdges.Merge(m, src)
}
func (m *Status_TotalEdges) XXX_Size() int {
return xxx_messageInfo_Status_TotalEdges.Size(m)
@@ -188,16 +199,17 @@
func (m *Status_BuildStarted) String() string { return proto.CompactTextString(m) }
func (*Status_BuildStarted) ProtoMessage() {}
func (*Status_BuildStarted) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 1}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 1}
}
+
func (m *Status_BuildStarted) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_BuildStarted.Unmarshal(m, b)
}
func (m *Status_BuildStarted) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_BuildStarted.Marshal(b, m, deterministic)
}
-func (dst *Status_BuildStarted) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_BuildStarted.Merge(dst, src)
+func (m *Status_BuildStarted) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_BuildStarted.Merge(m, src)
}
func (m *Status_BuildStarted) XXX_Size() int {
return xxx_messageInfo_Status_BuildStarted.Size(m)
@@ -232,16 +244,17 @@
func (m *Status_BuildFinished) String() string { return proto.CompactTextString(m) }
func (*Status_BuildFinished) ProtoMessage() {}
func (*Status_BuildFinished) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 2}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 2}
}
+
func (m *Status_BuildFinished) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_BuildFinished.Unmarshal(m, b)
}
func (m *Status_BuildFinished) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_BuildFinished.Marshal(b, m, deterministic)
}
-func (dst *Status_BuildFinished) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_BuildFinished.Merge(dst, src)
+func (m *Status_BuildFinished) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_BuildFinished.Merge(m, src)
}
func (m *Status_BuildFinished) XXX_Size() int {
return xxx_messageInfo_Status_BuildFinished.Size(m)
@@ -276,16 +289,17 @@
func (m *Status_EdgeStarted) String() string { return proto.CompactTextString(m) }
func (*Status_EdgeStarted) ProtoMessage() {}
func (*Status_EdgeStarted) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 3}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 3}
}
+
func (m *Status_EdgeStarted) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_EdgeStarted.Unmarshal(m, b)
}
func (m *Status_EdgeStarted) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_EdgeStarted.Marshal(b, m, deterministic)
}
-func (dst *Status_EdgeStarted) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_EdgeStarted.Merge(dst, src)
+func (m *Status_EdgeStarted) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_EdgeStarted.Merge(m, src)
}
func (m *Status_EdgeStarted) XXX_Size() int {
return xxx_messageInfo_Status_EdgeStarted.Size(m)
@@ -353,7 +367,11 @@
// Exit status (0 for success).
Status *int32 `protobuf:"zigzag32,3,opt,name=status" json:"status,omitempty"`
// Edge output, may contain ANSI codes.
- Output *string `protobuf:"bytes,4,opt,name=output" json:"output,omitempty"`
+ Output *string `protobuf:"bytes,4,opt,name=output" json:"output,omitempty"`
+ // Number of milliseconds spent executing in user mode
+ UserTime *uint32 `protobuf:"varint,5,opt,name=user_time,json=userTime" json:"user_time,omitempty"`
+ // Number of milliseconds spent executing in kernel mode
+ SystemTime *uint32 `protobuf:"varint,6,opt,name=system_time,json=systemTime" json:"system_time,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -363,16 +381,17 @@
func (m *Status_EdgeFinished) String() string { return proto.CompactTextString(m) }
func (*Status_EdgeFinished) ProtoMessage() {}
func (*Status_EdgeFinished) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 4}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 4}
}
+
func (m *Status_EdgeFinished) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_EdgeFinished.Unmarshal(m, b)
}
func (m *Status_EdgeFinished) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_EdgeFinished.Marshal(b, m, deterministic)
}
-func (dst *Status_EdgeFinished) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_EdgeFinished.Merge(dst, src)
+func (m *Status_EdgeFinished) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_EdgeFinished.Merge(m, src)
}
func (m *Status_EdgeFinished) XXX_Size() int {
return xxx_messageInfo_Status_EdgeFinished.Size(m)
@@ -411,8 +430,22 @@
return ""
}
+func (m *Status_EdgeFinished) GetUserTime() uint32 {
+ if m != nil && m.UserTime != nil {
+ return *m.UserTime
+ }
+ return 0
+}
+
+func (m *Status_EdgeFinished) GetSystemTime() uint32 {
+ if m != nil && m.SystemTime != nil {
+ return *m.SystemTime
+ }
+ return 0
+}
+
type Status_Message struct {
- // Message priority level (INFO, WARNING, or ERROR).
+ // Message priority level (DEBUG, INFO, WARNING, ERROR).
Level *Status_Message_Level `protobuf:"varint,1,opt,name=level,enum=ninja.Status_Message_Level,def=0" json:"level,omitempty"`
// Info/warning/error message from Ninja.
Message *string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
@@ -425,16 +458,17 @@
func (m *Status_Message) String() string { return proto.CompactTextString(m) }
func (*Status_Message) ProtoMessage() {}
func (*Status_Message) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 5}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 5}
}
+
func (m *Status_Message) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_Message.Unmarshal(m, b)
}
func (m *Status_Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_Message.Marshal(b, m, deterministic)
}
-func (dst *Status_Message) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_Message.Merge(dst, src)
+func (m *Status_Message) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_Message.Merge(m, src)
}
func (m *Status_Message) XXX_Size() int {
return xxx_messageInfo_Status_Message.Size(m)
@@ -462,6 +496,7 @@
}
func init() {
+ proto.RegisterEnum("ninja.Status_Message_Level", Status_Message_Level_name, Status_Message_Level_value)
proto.RegisterType((*Status)(nil), "ninja.Status")
proto.RegisterType((*Status_TotalEdges)(nil), "ninja.Status.TotalEdges")
proto.RegisterType((*Status_BuildStarted)(nil), "ninja.Status.BuildStarted")
@@ -469,42 +504,46 @@
proto.RegisterType((*Status_EdgeStarted)(nil), "ninja.Status.EdgeStarted")
proto.RegisterType((*Status_EdgeFinished)(nil), "ninja.Status.EdgeFinished")
proto.RegisterType((*Status_Message)(nil), "ninja.Status.Message")
- proto.RegisterEnum("ninja.Status_Message_Level", Status_Message_Level_name, Status_Message_Level_value)
}
-func init() { proto.RegisterFile("frontend.proto", fileDescriptor_frontend_5a49d9b15a642005) }
+func init() {
+ proto.RegisterFile("frontend.proto", fileDescriptor_eca3873955a29cfe)
+}
-var fileDescriptor_frontend_5a49d9b15a642005 = []byte{
- // 496 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x53, 0xd1, 0x6e, 0xd3, 0x30,
- 0x14, 0xa5, 0x69, 0xd3, 0x34, 0x37, 0x6d, 0x28, 0x96, 0x40, 0x59, 0x10, 0xa2, 0xda, 0xd3, 0x78,
- 0x20, 0x48, 0xbc, 0x20, 0x10, 0x12, 0xa2, 0xd2, 0x06, 0x43, 0xd0, 0x49, 0xde, 0x24, 0x24, 0x5e,
- 0xaa, 0x74, 0xf6, 0x86, 0x51, 0xe2, 0x54, 0xb1, 0xbb, 0x5f, 0xe0, 0x7f, 0x78, 0xe0, 0xfb, 0x90,
- 0xaf, 0xed, 0x2c, 0x65, 0x7b, 0xcb, 0xf1, 0x3d, 0xe7, 0xde, 0x73, 0x8f, 0x1d, 0x48, 0xaf, 0xda,
- 0x46, 0x6a, 0x2e, 0x59, 0xb1, 0x6d, 0x1b, 0xdd, 0x90, 0x50, 0x0a, 0xf9, 0xab, 0x3c, 0xfc, 0x13,
- 0xc1, 0xf8, 0x5c, 0x97, 0x7a, 0xa7, 0xc8, 0x5b, 0x48, 0x74, 0xa3, 0xcb, 0x6a, 0xcd, 0xd9, 0x35,
- 0x57, 0xd9, 0x60, 0x31, 0x38, 0x4a, 0x5e, 0x67, 0x05, 0xf2, 0x0a, 0xcb, 0x29, 0x2e, 0x0c, 0xe1,
- 0xd8, 0xd4, 0x29, 0xe8, 0xee, 0x9b, 0x7c, 0x80, 0xd9, 0x66, 0x27, 0x2a, 0xb6, 0x56, 0xba, 0x6c,
- 0x35, 0x67, 0x59, 0x80, 0xe2, 0x7c, 0x5f, 0xbc, 0x34, 0x94, 0x73, 0xcb, 0xa0, 0xd3, 0x4d, 0x0f,
- 0x91, 0x25, 0xa4, 0xb6, 0xc1, 0x95, 0x90, 0x42, 0xfd, 0xe4, 0x2c, 0x1b, 0x62, 0x87, 0xa7, 0xf7,
- 0x74, 0x38, 0x71, 0x14, 0x6a, 0x67, 0x7a, 0x48, 0xde, 0xc3, 0xd4, 0x38, 0xef, 0x3c, 0x8c, 0xb0,
- 0xc3, 0xc1, 0x7e, 0x07, 0xe3, 0xd7, 0x5b, 0x48, 0xf8, 0x2d, 0x30, 0x2b, 0xa0, 0xba, 0x33, 0x10,
- 0xde, 0xb7, 0x82, 0x91, 0x77, 0xf3, 0x71, 0x5c, 0x37, 0xfe, 0x15, 0x44, 0x35, 0x57, 0xaa, 0xbc,
- 0xe6, 0xd9, 0x18, 0xa5, 0x8f, 0xf7, 0xa5, 0xdf, 0x6c, 0x91, 0x7a, 0x56, 0xfe, 0x12, 0xe0, 0x36,
- 0x4e, 0xf2, 0xfc, 0x6e, 0xfa, 0xb3, 0x7e, 0xc6, 0xf9, 0x17, 0x98, 0xf6, 0x03, 0x24, 0x0b, 0x48,
- 0xb6, 0x65, 0x5b, 0x56, 0x15, 0xaf, 0x84, 0xaa, 0x9d, 0xa0, 0x7f, 0x44, 0x32, 0x88, 0x6e, 0x78,
- 0xbb, 0x69, 0x14, 0xc7, 0xfb, 0x98, 0x50, 0x0f, 0xf3, 0x87, 0x30, 0xdb, 0x8b, 0x32, 0xff, 0x3b,
- 0x80, 0xa4, 0x17, 0x0d, 0x49, 0x21, 0x10, 0xcc, 0xf5, 0x0c, 0x04, 0x23, 0xcf, 0x00, 0x30, 0xd6,
- 0xb5, 0x16, 0xb5, 0xed, 0x36, 0xa3, 0x31, 0x9e, 0x5c, 0x88, 0x9a, 0x93, 0x27, 0x30, 0x16, 0x72,
- 0xbb, 0xd3, 0x2a, 0x1b, 0x2e, 0x86, 0x47, 0x31, 0x75, 0xc8, 0x38, 0x68, 0x76, 0x1a, 0x0b, 0x23,
- 0x2c, 0x78, 0x48, 0x08, 0x8c, 0x18, 0x57, 0x97, 0x98, 0x72, 0x4c, 0xf1, 0xdb, 0xb0, 0x2f, 0x9b,
- 0xba, 0x2e, 0x25, 0xc3, 0x04, 0x63, 0xea, 0xa1, 0xad, 0x48, 0xd5, 0x54, 0x3c, 0x8b, 0xec, 0x26,
- 0x0e, 0xe6, 0x02, 0xa6, 0xfd, 0x3b, 0xb9, 0x63, 0xfc, 0x00, 0x26, 0x5c, 0xb2, 0xbe, 0xed, 0x88,
- 0x4b, 0xe6, 0x4d, 0x2b, 0xbc, 0x1a, 0x7c, 0x6b, 0x8f, 0xa8, 0x43, 0xe6, 0xdc, 0xba, 0xc4, 0x17,
- 0x14, 0x53, 0x87, 0xf2, 0xdf, 0x03, 0x88, 0xdc, 0x25, 0x92, 0x37, 0x10, 0x56, 0xfc, 0x86, 0x57,
- 0x38, 0x29, 0xfd, 0xff, 0x99, 0x3a, 0x56, 0xf1, 0xd5, 0x50, 0xde, 0x8d, 0x4e, 0x57, 0x27, 0x67,
- 0xd4, 0xf2, 0xcd, 0x26, 0xfe, 0x95, 0x04, 0x76, 0x47, 0x07, 0x0f, 0x5f, 0x40, 0x88, 0x7c, 0x32,
- 0x01, 0x54, 0xcc, 0x1f, 0x90, 0x04, 0xa2, 0xef, 0x1f, 0xe9, 0xea, 0x74, 0xf5, 0x69, 0x3e, 0x20,
- 0x31, 0x84, 0xc7, 0x94, 0x9e, 0xd1, 0x79, 0xb0, 0x24, 0x9f, 0x87, 0x3f, 0x52, 0x9c, 0xb8, 0xf6,
- 0x7f, 0xf5, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2e, 0x8c, 0xef, 0xcb, 0xe0, 0x03, 0x00, 0x00,
+var fileDescriptor_eca3873955a29cfe = []byte{
+ // 539 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x54, 0xd1, 0x6e, 0xd3, 0x4a,
+ 0x10, 0xbd, 0x4e, 0xe2, 0x38, 0x1e, 0x27, 0xb9, 0x61, 0x25, 0x90, 0xeb, 0x0a, 0x35, 0xea, 0x53,
+ 0x5f, 0x08, 0x12, 0x42, 0x42, 0x20, 0x24, 0x44, 0x44, 0x5a, 0x8a, 0x20, 0x95, 0xb6, 0x45, 0x48,
+ 0xbc, 0x44, 0x4e, 0x77, 0x5a, 0x8c, 0xec, 0x75, 0xe4, 0xdd, 0x54, 0xe2, 0x37, 0xf8, 0x09, 0xfe,
+ 0x80, 0xaf, 0xe3, 0x01, 0xed, 0xec, 0xda, 0x75, 0x68, 0xdf, 0x7c, 0x76, 0xce, 0x9c, 0x39, 0x7b,
+ 0x76, 0x64, 0x18, 0x5f, 0x55, 0xa5, 0xd4, 0x28, 0xc5, 0x6c, 0x53, 0x95, 0xba, 0x64, 0xbe, 0xcc,
+ 0xe4, 0xf7, 0xf4, 0xf0, 0x4f, 0x00, 0xfd, 0x73, 0x9d, 0xea, 0xad, 0x62, 0x2f, 0x21, 0xd2, 0xa5,
+ 0x4e, 0xf3, 0x15, 0x8a, 0x6b, 0x54, 0xb1, 0x37, 0xf5, 0x8e, 0xa2, 0x67, 0xf1, 0x8c, 0x78, 0x33,
+ 0xcb, 0x99, 0x5d, 0x18, 0xc2, 0xc2, 0xd4, 0x39, 0xe8, 0xe6, 0x9b, 0xbd, 0x81, 0xd1, 0x7a, 0x9b,
+ 0xe5, 0x62, 0xa5, 0x74, 0x5a, 0x69, 0x14, 0x71, 0x87, 0x9a, 0x93, 0xdd, 0xe6, 0xb9, 0xa1, 0x9c,
+ 0x5b, 0x06, 0x1f, 0xae, 0x5b, 0x88, 0xcd, 0x61, 0x6c, 0x05, 0xae, 0x32, 0x99, 0xa9, 0x6f, 0x28,
+ 0xe2, 0x2e, 0x29, 0xec, 0xdf, 0xa3, 0x70, 0xec, 0x28, 0xdc, 0xce, 0xac, 0x21, 0x7b, 0x0d, 0x43,
+ 0xe3, 0xbc, 0xf1, 0xd0, 0x23, 0x85, 0xbd, 0x5d, 0x05, 0xe3, 0xb7, 0xb6, 0x10, 0xe1, 0x2d, 0x30,
+ 0x57, 0xa0, 0xee, 0xc6, 0x80, 0x7f, 0xdf, 0x15, 0x4c, 0x7b, 0x33, 0x9f, 0xc6, 0x35, 0xe3, 0x9f,
+ 0x42, 0x50, 0xa0, 0x52, 0xe9, 0x35, 0xc6, 0x7d, 0x6a, 0x7d, 0xb8, 0xdb, 0xfa, 0xc9, 0x16, 0x79,
+ 0xcd, 0x4a, 0x9e, 0x00, 0xdc, 0xc6, 0xc9, 0x0e, 0xee, 0xa6, 0x3f, 0x6a, 0x67, 0x9c, 0x7c, 0x80,
+ 0x61, 0x3b, 0x40, 0x36, 0x85, 0x68, 0x93, 0x56, 0x69, 0x9e, 0x63, 0x9e, 0xa9, 0xc2, 0x35, 0xb4,
+ 0x8f, 0x58, 0x0c, 0xc1, 0x0d, 0x56, 0xeb, 0x52, 0x21, 0xbd, 0xc7, 0x80, 0xd7, 0x30, 0xf9, 0x1f,
+ 0x46, 0x3b, 0x51, 0x26, 0xbf, 0x3d, 0x88, 0x5a, 0xd1, 0xb0, 0x31, 0x74, 0x32, 0xe1, 0x34, 0x3b,
+ 0x99, 0x60, 0x8f, 0x01, 0x28, 0xd6, 0x95, 0xce, 0x0a, 0xab, 0x36, 0xe2, 0x21, 0x9d, 0x5c, 0x64,
+ 0x05, 0xb2, 0x47, 0xd0, 0xcf, 0xe4, 0x66, 0xab, 0x55, 0xdc, 0x9d, 0x76, 0x8f, 0x42, 0xee, 0x90,
+ 0x71, 0x50, 0x6e, 0x35, 0x15, 0x7a, 0x54, 0xa8, 0x21, 0x63, 0xd0, 0x13, 0xa8, 0x2e, 0x29, 0xe5,
+ 0x90, 0xd3, 0xb7, 0x61, 0x5f, 0x96, 0x45, 0x91, 0x4a, 0x41, 0x09, 0x86, 0xbc, 0x86, 0xb6, 0x22,
+ 0x55, 0x99, 0x63, 0x1c, 0xd8, 0x9b, 0x38, 0x98, 0xfc, 0xf2, 0x60, 0xd8, 0x7e, 0x94, 0x3b, 0xce,
+ 0xf7, 0x60, 0x80, 0x52, 0xb4, 0x7d, 0x07, 0x28, 0x45, 0xed, 0x5a, 0xd1, 0xdb, 0xd0, 0xb2, 0x3d,
+ 0xe0, 0x0e, 0x99, 0x73, 0x6b, 0x93, 0x56, 0x28, 0xe4, 0x0e, 0xb1, 0x7d, 0x08, 0xb7, 0x0a, 0x2b,
+ 0xab, 0xe5, 0x93, 0xd6, 0xc0, 0x1c, 0x90, 0xd8, 0x01, 0x44, 0xea, 0x87, 0xd2, 0x58, 0xd8, 0x72,
+ 0xdf, 0xbe, 0x9f, 0x3d, 0x32, 0x84, 0xe4, 0xa7, 0x07, 0x81, 0xdb, 0x01, 0xf6, 0x02, 0xfc, 0x1c,
+ 0x6f, 0x30, 0x27, 0x9f, 0xe3, 0x7f, 0xb7, 0xdc, 0xb1, 0x66, 0x1f, 0x0d, 0xe5, 0x55, 0xef, 0x74,
+ 0x79, 0x7c, 0xc6, 0x2d, 0xdf, 0x04, 0x51, 0x2f, 0x59, 0xc7, 0x46, 0xe4, 0xe0, 0xe1, 0x73, 0xf0,
+ 0x89, 0xcf, 0x06, 0x40, 0x1d, 0x93, 0xff, 0x58, 0x04, 0xc1, 0x97, 0xb7, 0x7c, 0x79, 0xba, 0x3c,
+ 0x99, 0x78, 0x2c, 0x04, 0x7f, 0xc1, 0xf9, 0x19, 0x9f, 0x74, 0xcc, 0xe7, 0xbb, 0xc5, 0xfc, 0xf3,
+ 0xc9, 0xa4, 0x3b, 0x67, 0xef, 0xbb, 0x5f, 0xc7, 0x34, 0x7c, 0x55, 0xff, 0x1f, 0xfe, 0x06, 0x00,
+ 0x00, 0xff, 0xff, 0xaf, 0x93, 0x48, 0xcf, 0x2a, 0x04, 0x00, 0x00,
}
diff --git a/ui/status/ninja_frontend/frontend.proto b/ui/status/ninja_frontend/frontend.proto
index 13fd535..baa0046 100644
--- a/ui/status/ninja_frontend/frontend.proto
+++ b/ui/status/ninja_frontend/frontend.proto
@@ -61,6 +61,10 @@
optional sint32 status = 3;
// Edge output, may contain ANSI codes.
optional string output = 4;
+ // Number of milliseconds spent executing in user mode
+ optional uint32 user_time = 5;
+ // Number of milliseconds spent executing in kernel mode
+ optional uint32 system_time = 6;
}
message Message {
@@ -68,8 +72,9 @@
INFO = 0;
WARNING = 1;
ERROR = 2;
+ DEBUG = 3;
}
- // Message priority level (INFO, WARNING, or ERROR).
+ // Message priority level (DEBUG, INFO, WARNING, ERROR).
optional Level level = 1 [default = INFO];
// Info/warning/error message from Ninja.
optional string message = 2;