Merge "Static variant of a stubs lib is correctly tracked"
diff --git a/README.md b/README.md
index 74d49bb..44a98f3 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@
all Android.bp files.
For a list of valid module types and their properties see
-[$OUT_DIR/soong/.bootstrap/docs/soong_build.html](http://go/Android.bp).
+[$OUT_DIR/soong/docs/soong_build.html](http://go/Android.bp).
### Globs
diff --git a/android/makevars.go b/android/makevars.go
index 3a7ec6e..366bb6b 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -22,6 +22,8 @@
"strconv"
"strings"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
)
@@ -38,7 +40,21 @@
type MakeVarsContext interface {
Config() Config
DeviceConfig() DeviceConfig
- SingletonContext() SingletonContext
+ AddNinjaFileDeps(deps ...string)
+ Fs() pathtools.FileSystem
+
+ ModuleName(module blueprint.Module) string
+ ModuleDir(module blueprint.Module) string
+ ModuleSubDir(module blueprint.Module) string
+ ModuleType(module blueprint.Module) string
+ BlueprintFile(module blueprint.Module) string
+
+ ModuleErrorf(module blueprint.Module, format string, args ...interface{})
+ Errorf(format string, args ...interface{})
+ Failed() bool
+
+ VisitAllModules(visit func(Module))
+ VisitAllModulesIf(pred func(Module) bool, visit func(Module))
// Verify the make variable matches the Soong version, fail the build
// if it does not. If the make variable is empty, just set it.
@@ -66,6 +82,8 @@
CheckRaw(name, value string)
}
+var _ PathContext = MakeVarsContext(nil)
+
type MakeVarsProvider func(ctx MakeVarsContext)
func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
@@ -92,8 +110,8 @@
var makeVarsProviders []makeVarsProvider
type makeVarsContext struct {
+ SingletonContext
config Config
- ctx SingletonContext
pctx PackageContext
vars []makeVarsVariable
}
@@ -121,9 +139,8 @@
vars := []makeVarsVariable{}
for _, provider := range makeVarsProviders {
mctx := &makeVarsContext{
- config: ctx.Config(),
- ctx: ctx,
- pctx: provider.pctx,
+ SingletonContext: ctx,
+ pctx: provider.pctx,
}
provider.call(mctx)
@@ -229,22 +246,14 @@
return buf.Bytes()
}
-func (c *makeVarsContext) Config() Config {
- return c.config
-}
-
func (c *makeVarsContext) DeviceConfig() DeviceConfig {
- return DeviceConfig{c.config.deviceConfig}
-}
-
-func (c *makeVarsContext) SingletonContext() SingletonContext {
- return c.ctx
+ return DeviceConfig{c.Config().deviceConfig}
}
var ninjaDescaper = strings.NewReplacer("$$", "$")
func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
- s, err := c.ctx.Eval(c.pctx, ninjaStr)
+ s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
if err != nil {
return "", err
}
@@ -265,7 +274,7 @@
func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
value, err := c.Eval(ninjaStr)
if err != nil {
- c.ctx.Errorf(err.Error())
+ c.SingletonContext.Errorf(err.Error())
}
c.addVariableRaw(name, value, strict, sort)
}
diff --git a/android/paths.go b/android/paths.go
index 4b84c97..0c65b83 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -244,7 +244,7 @@
}
path := filepath.Clean(p)
if !strings.HasPrefix(path, prefix) {
- reportPathErrorf(ctx, "Path '%s' is not in module source directory '%s'", p, prefix)
+ reportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
continue
}
@@ -263,9 +263,9 @@
}
// PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's
-// local source directory. If none are provided, use the default if it exists.
+// local source directory. If input is nil, use the default if it exists. If input is empty, returns nil.
func PathsWithOptionalDefaultForModuleSrc(ctx ModuleContext, input []string, def string) Paths {
- if len(input) > 0 {
+ if input != nil {
return PathsForModuleSrc(ctx, input)
}
// Use Glob so that if the default doesn't exist, a dependency is added so that when it
@@ -505,7 +505,7 @@
// absolute path already checked by validateSafePath
if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
- return ret, fmt.Errorf("source path %s is in output", ret.String())
+ return ret, fmt.Errorf("source path %q is in output", ret.String())
}
return ret, err
@@ -521,7 +521,7 @@
// absolute path already checked by validatePath
if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
- return ret, fmt.Errorf("source path %s is in output", ret.String())
+ return ret, fmt.Errorf("source path %q is in output", ret.String())
}
return ret, nil
@@ -575,7 +575,7 @@
} else if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
reportPathErrorf(ctx, "%s: %s", path, err.Error())
} else if !exists {
- reportPathErrorf(ctx, "source path %s does not exist", path)
+ reportPathErrorf(ctx, "source path %q does not exist", path)
}
return path
}
@@ -740,7 +740,7 @@
if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
reportPathErrorf(ctx, "%s: %s", path, err.Error())
} else if !exists {
- reportPathErrorf(ctx, "module source path %s does not exist", path)
+ reportPathErrorf(ctx, "module source path %q does not exist", path)
}
return path
diff --git a/android/singleton.go b/android/singleton.go
index f926435..05ec6b5 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -22,6 +22,7 @@
// SingletonContext
type SingletonContext interface {
Config() Config
+ DeviceConfig() DeviceConfig
ModuleName(module blueprint.Module) string
ModuleDir(module blueprint.Module) string
@@ -93,6 +94,10 @@
return s.SingletonContext.Config().(Config)
}
+func (s singletonContextAdaptor) DeviceConfig() DeviceConfig {
+ return DeviceConfig{s.Config().deviceConfig}
+}
+
func (s singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
s.SingletonContext.Variable(pctx.PackageContext, name, value)
}
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index aef8944..abe7917 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -188,6 +188,7 @@
"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
"LOCAL_PRIVILEGED_MODULE": "privileged",
"LOCAL_AAPT_INCLUDE_ALL_RESOURCES": "aapt_include_all_resources",
+ "LOCAL_USE_EMBEDDED_NATIVE_LIBS": "use_embedded_native_libs",
"LOCAL_DEX_PREOPT": "dex_preopt.enabled",
"LOCAL_DEX_PREOPT_APP_IMAGE": "dex_preopt.app_image",
diff --git a/apex/apex.go b/apex/apex.go
index 3584896..95cee0c 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -136,7 +136,9 @@
pctx.HostBinToolVariable("zip2zip", "zip2zip")
pctx.HostBinToolVariable("zipalign", "zipalign")
- android.RegisterModuleType("apex", ApexBundleFactory)
+ android.RegisterModuleType("apex", apexBundleFactory)
+ android.RegisterModuleType("apex_test", testApexBundleFactory)
+ android.RegisterModuleType("apex_defaults", defaultsFactory)
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("apex_deps", apexDepsMutator)
@@ -147,13 +149,18 @@
// Mark the direct and transitive dependencies of apex bundles so that they
// can be built for the apex bundles.
func apexDepsMutator(mctx android.TopDownMutatorContext) {
- if _, ok := mctx.Module().(*apexBundle); ok {
+ if a, ok := mctx.Module().(*apexBundle); ok {
apexBundleName := mctx.ModuleName()
mctx.WalkDeps(func(child, parent android.Module) bool {
depName := mctx.OtherModuleName(child)
// If the parent is apexBundle, this child is directly depended.
_, directDep := parent.(*apexBundle)
- android.UpdateApexDependency(apexBundleName, depName, directDep)
+ if a.installable() && !a.testApex {
+ // TODO(b/123892969): Workaround for not having any way to annotate test-apexs
+ // non-installable apex's cannot be installed and so should not prevent libraries from being
+ // installed to the system.
+ android.UpdateApexDependency(apexBundleName, depName, directDep)
+ }
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() {
am.BuildForApex(apexBundleName)
@@ -369,6 +376,8 @@
filesInfo []apexFile
flattened bool
+
+ testApex bool
}
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -1046,7 +1055,7 @@
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
moduleNames := []string{}
if a.installable() {
- a.androidMkForFiles(w, name, moduleDir)
+ moduleNames = a.androidMkForFiles(w, name, moduleDir)
}
if a.flattened && apexType.image() {
@@ -1085,9 +1094,18 @@
}}
}
-func ApexBundleFactory() android.Module {
+func testApexBundleFactory() android.Module {
+ return ApexBundleFactory( /*testApex*/ true)
+}
+
+func apexBundleFactory() android.Module {
+ return ApexBundleFactory( /*testApex*/ false)
+}
+
+func ApexBundleFactory(testApex bool) android.Module {
module := &apexBundle{
outputFiles: map[apexPackaging]android.WritablePath{},
+ testApex: testApex,
}
module.AddProperties(&module.properties)
module.AddProperties(&module.targetProperties)
@@ -1098,3 +1116,31 @@
android.InitDefaultableModule(module)
return module
}
+
+//
+// Defaults
+//
+type Defaults struct {
+ android.ModuleBase
+ android.DefaultsModuleBase
+}
+
+func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func defaultsFactory() android.Module {
+ return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+ module := &Defaults{}
+
+ module.AddProperties(props...)
+ module.AddProperties(
+ &apexBundleProperties{},
+ &apexTargetBundleProperties{},
+ )
+
+ android.InitDefaultsModule(module)
+ return module
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 56ddd5f..2c7f285 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -31,8 +31,11 @@
defer teardown(buildDir)
ctx := android.NewTestArchContext()
- ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(ApexBundleFactory))
+ ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory))
+ ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory))
ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory))
+ ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("apex_deps", apexDepsMutator)
@@ -201,8 +204,8 @@
// Minimal test
func TestBasicApex(t *testing.T) {
ctx := testApex(t, `
- apex {
- name: "myapex",
+ apex_defaults {
+ name: "myapex-defaults",
key: "myapex.key",
native_shared_libs: ["mylib"],
multilib: {
@@ -212,6 +215,11 @@
}
}
+ apex {
+ name: "myapex",
+ defaults: ["myapex-defaults"],
+ }
+
apex_key {
name: "myapex.key",
public_key: "testkey.avbpubkey",
@@ -897,6 +905,105 @@
ensureContains(t, cFlags, "-Imy_include")
}
+func TestNonTestApex(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib_common"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib_common",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ module := ctx.ModuleForTests("myapex", "android_common_myapex")
+ apexRule := module.Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+
+ if apex, ok := module.Module().(*apexBundle); !ok || apex.testApex {
+ t.Log("Apex was a test apex!")
+ t.Fail()
+ }
+ // Ensure that main rule creates an output
+ ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
+
+ // Ensure that apex variant is created for the direct dep
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared_myapex")
+
+ // Ensure that both direct and indirect deps are copied into apex
+ ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so")
+
+ // Ensure that the platform variant ends with _core_shared
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared")
+
+ if !android.InAnyApex("mylib_common") {
+ t.Log("Found mylib_common not in any apex!")
+ t.Fail()
+ }
+}
+
+func TestTestApex(t *testing.T) {
+ if android.InAnyApex("mylib_common_test") {
+ t.Fatal("mylib_common_test must not be used in any other tests since this checks that global state is not updated in an illegal way!")
+ }
+ ctx := testApex(t, `
+ apex_test {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib_common_test"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib_common_test",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ module := ctx.ModuleForTests("myapex", "android_common_myapex")
+ apexRule := module.Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+
+ if apex, ok := module.Module().(*apexBundle); !ok || !apex.testApex {
+ t.Log("Apex was not a test apex!")
+ t.Fail()
+ }
+ // Ensure that main rule creates an output
+ ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
+
+ // Ensure that apex variant is created for the direct dep
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_core_shared_myapex")
+
+ // Ensure that both direct and indirect deps are copied into apex
+ ensureContains(t, copyCmds, "image.apex/lib64/mylib_common_test.so")
+
+ // Ensure that the platform variant ends with _core_shared
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_core_shared")
+
+ if android.InAnyApex("mylib_common_test") {
+ t.Log("Found mylib_common_test in some apex!")
+ t.Fail()
+ }
+}
+
func TestApexWithTarget(t *testing.T) {
ctx := testApex(t, `
apex {
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
index 4906ea2..81bc398 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/gen_stub_libs.py
@@ -119,9 +119,12 @@
return True
if 'platform-only' in version.tags:
return True
- if 'vndk' in version.tags and not vndk:
- return True
- if 'apex' in version.tags and not apex:
+
+ no_vndk_no_apex = 'vndk' not in version.tags and 'apex' not in version.tags
+ keep = no_vndk_no_apex or \
+ ('vndk' in version.tags and vndk) or \
+ ('apex' in version.tags and apex)
+ if not keep:
return True
if not symbol_in_arch(version.tags, arch):
return True
@@ -132,9 +135,11 @@
def should_omit_symbol(symbol, arch, api, vndk, apex):
"""Returns True if the symbol should be omitted."""
- if not vndk and 'vndk' in symbol.tags:
- return True
- if not apex and 'apex' in symbol.tags:
+ no_vndk_no_apex = 'vndk' not in symbol.tags and 'apex' not in symbol.tags
+ keep = no_vndk_no_apex or \
+ ('vndk' in symbol.tags and vndk) or \
+ ('apex' in symbol.tags and apex)
+ if not keep:
return True
if not symbol_in_arch(symbol.tags, arch):
return True
diff --git a/cc/makevars.go b/cc/makevars.go
index d91735f..4a9ade2 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -100,7 +100,7 @@
// Filter vendor_public_library that are exported to make
exportedVendorPublicLibraries := []string{}
- ctx.SingletonContext().VisitAllModules(func(module android.Module) {
+ ctx.VisitAllModules(func(module android.Module) {
if ccModule, ok := module.(*Module); ok {
baseName := ccModule.BaseModuleName()
if inList(baseName, vendorPublicLibraries) && module.ExportedToMake() {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 1b09f88..3ae4452 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -53,6 +53,7 @@
"OpenMAXAL",
"OpenSLES",
"stdc++",
+ "sync",
"vulkan",
"z",
}
diff --git a/cc/test_gen_stub_libs.py b/cc/test_gen_stub_libs.py
index 594c1bc..2ee9886 100755
--- a/cc/test_gen_stub_libs.py
+++ b/cc/test_gen_stub_libs.py
@@ -751,6 +751,8 @@
wibble;
wizzes; # vndk
waggle; # apex
+ bubble; # apex vndk
+ duddle; # vndk apex
} VERSION_2;
VERSION_5 { # versioned=14
@@ -771,6 +773,8 @@
void qux() {}
void wibble() {}
void waggle() {}
+ void bubble() {}
+ void duddle() {}
void wobble() {}
""")
self.assertEqual(expected_src, src_file.getvalue())
@@ -788,6 +792,8 @@
global:
wibble;
waggle;
+ bubble;
+ duddle;
} VERSION_2;
""")
self.assertEqual(expected_version, version_file.getvalue())
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 6a3d579..330c5dd 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -172,7 +172,8 @@
stat := &status.Status{}
defer stat.Finish()
- stat.AddOutput(terminal.NewStatusOutput(writer, ""))
+ stat.AddOutput(terminal.NewStatusOutput(writer, "",
+ build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
var failures failureCount
stat.AddOutput(&failures)
@@ -389,7 +390,8 @@
Thread: mpctx.Tracer.NewThread(product),
Status: &status.Status{},
}}
- ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, ""))
+ ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "",
+ build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
config := build.NewConfig(ctx, flag.Args()...)
config.Environment().Set("OUT_DIR", outDir)
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 0380368..d6999c5 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -78,7 +78,8 @@
stat := &status.Status{}
defer stat.Finish()
- stat.AddOutput(terminal.NewStatusOutput(writer, os.Getenv("NINJA_STATUS")))
+ stat.AddOutput(terminal.NewStatusOutput(writer, os.Getenv("NINJA_STATUS"),
+ build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
stat.AddOutput(trace.StatusTracer())
build.SetupSignals(log, cancel, func() {
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 3725146..319e36e 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -91,7 +91,6 @@
DexLocation string // dex location on device
BuildPath string
DexPath string
- UseEmbeddedDex bool
UncompressedDex bool
HasApkLibraries bool
PreoptFlags []string
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 6e520f1..d949852 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -67,7 +67,6 @@
DexLocation: "",
BuildPath: "",
DexPath: "",
- UseEmbeddedDex: false,
UncompressedDex: false,
HasApkLibraries: false,
PreoptFlags: nil,
diff --git a/java/aar.go b/java/aar.go
index b01962a..f6a3d3a 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -53,11 +53,13 @@
Aapt_include_all_resources *bool
// list of directories relative to the Blueprints file containing assets.
- // Defaults to "assets"
+ // Defaults to ["assets"] if a directory called assets exists. Set to []
+ // to disable the default.
Asset_dirs []string
// list of directories relative to the Blueprints file containing
- // Android resources
+ // Android resources. Defaults to ["res"] if a directory called res exists.
+ // Set to [] to disable the default.
Resource_dirs []string
// path to AndroidManifest.xml. If unset, defaults to "AndroidManifest.xml".
@@ -73,6 +75,7 @@
rTxt android.Path
extraAaptPackagesFile android.Path
isLibrary bool
+ uncompressedJNI bool
aaptProperties aaptProperties
}
@@ -179,11 +182,13 @@
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
- manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary)
+ manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary, a.uncompressedJNI)
linkFlags, linkDeps, resDirs, overlayDirs, rroDirs := a.aapt2Flags(ctx, sdkContext, manifestPath)
rroDirs = append(rroDirs, staticRRODirs...)
+ // TODO(b/124035856): stop de-duping when there are no more dupe resource dirs.
+ rroDirs = android.FirstUniquePaths(rroDirs)
linkFlags = append(linkFlags, libFlags...)
linkDeps = append(linkDeps, libDeps...)
@@ -326,7 +331,7 @@
}
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- a.isLibrary = true
+ a.aapt.isLibrary = true
a.aapt.buildActions(ctx, sdkContext(a))
ctx.CheckbuildFile(a.proguardOptionsFile)
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 36f24ff..6d4399d 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -15,12 +15,13 @@
package java
import (
- "android/soong/java/config"
+ "fmt"
"strings"
"github.com/google/blueprint"
"android/soong/android"
+ "android/soong/java/config"
)
var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
@@ -43,11 +44,22 @@
"libs")
func manifestMerger(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
- staticLibManifests android.Paths, isLibrary bool) android.Path {
+ staticLibManifests android.Paths, isLibrary bool, uncompressedJNI bool) android.Path {
var args []string
if isLibrary {
args = append(args, "--library")
+ } else {
+ minSdkVersion, err := sdkVersionToNumber(ctx, sdkContext.minSdkVersion())
+ if err != nil {
+ ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ }
+ if minSdkVersion >= 23 {
+ args = append(args, fmt.Sprintf("--extract-native-libs=%v", !uncompressedJNI))
+ } else if uncompressedJNI {
+ ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
+ minSdkVersion)
+ }
}
// Inject minSdkVersion into the manifest
diff --git a/java/androidmk.go b/java/androidmk.go
index 089ed4f..d86e71f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -203,6 +203,11 @@
Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
Extra: []android.AndroidMkExtraFunc{
func(w io.Writer, outputFile android.Path) {
+ // TODO(jungjw): This, outputting two LOCAL_MODULE lines, works, but is not ideal. Find a better solution.
+ if app.Name() != app.installApkName {
+ fmt.Fprintln(w, "# Overridden by PRODUCT_PACKAGE_NAME_OVERRIDES")
+ fmt.Fprintln(w, "LOCAL_MODULE :=", app.installApkName)
+ }
fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", app.exportPackage.String())
if app.dexJarFile != nil {
fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String())
@@ -247,8 +252,8 @@
}
fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
- if len(app.appProperties.Overrides) > 0 {
- fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES := "+strings.Join(app.appProperties.Overrides, " "))
+ if overriddenPkgs := app.getOverriddenPackages(); len(overriddenPkgs) > 0 {
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(overriddenPkgs, " "))
}
for _, jniLib := range app.installJniLibs {
@@ -262,6 +267,17 @@
}
}
+func (a *AndroidApp) getOverriddenPackages() []string {
+ var overridden []string
+ if len(a.appProperties.Overrides) > 0 {
+ overridden = append(overridden, a.appProperties.Overrides...)
+ }
+ if a.Name() != a.installApkName {
+ overridden = append(overridden, a.Name())
+ }
+ return overridden
+}
+
func (a *AndroidTest) AndroidMk() android.AndroidMkData {
data := a.AndroidApp.AndroidMk()
data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
diff --git a/java/app.go b/java/app.go
index 08714f2..47f4f0d 100644
--- a/java/app.go
+++ b/java/app.go
@@ -68,7 +68,11 @@
// list of native libraries that will be provided in or alongside the resulting jar
Jni_libs []string `android:"arch_variant"`
- EmbedJNI bool `blueprint:"mutated"`
+ // Store native libraries uncompressed in the APK and set the android:extractNativeLibs="false" manifest
+ // flag so that they are used from inside the APK at runtime. Defaults to true for android_test modules unless
+ // sdk_version or min_sdk_version is set to a version that doesn't support it (<23), defaults to false for other
+ // module types where the native libraries are generally preinstalled outside the APK.
+ Use_embedded_native_libs *bool
}
type AndroidApp struct {
@@ -136,9 +140,21 @@
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ a.aapt.uncompressedJNI = a.shouldUncompressJNI(ctx)
a.generateAndroidBuildActions(ctx)
}
+// shouldUncompressJNI returns true if the native libraries should be stored in the APK uncompressed and the
+// extractNativeLibs application flag should be set to false in the manifest.
+func (a *AndroidApp) shouldUncompressJNI(ctx android.ModuleContext) bool {
+ minSdkVersion, err := sdkVersionToNumber(ctx, a.minSdkVersion())
+ if err != nil {
+ ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.minSdkVersion(), err)
+ }
+
+ return minSdkVersion >= 23 && Bool(a.appProperties.Use_embedded_native_libs)
+}
+
// Returns whether this module should have the dex file stored uncompressed in the APK.
func (a *AndroidApp) shouldUncompressDex(ctx android.ModuleContext) bool {
if ctx.Config().UnbundledBuild() {
@@ -230,10 +246,10 @@
func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
var jniJarFile android.WritablePath
if len(jniLibs) > 0 {
- embedJni := ctx.Config().UnbundledBuild() || a.appProperties.EmbedJNI
+ embedJni := ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs)
if embedJni {
jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
- TransformJniLibsToJar(ctx, jniJarFile, jniLibs)
+ TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.shouldUncompressJNI(ctx))
} else {
a.installJniLibs = jniLibs
}
@@ -428,7 +444,7 @@
module.Module.properties.Instrument = true
module.Module.properties.Installable = proptools.BoolPtr(true)
- module.appProperties.EmbedJNI = true
+ module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
module.AddProperties(
@@ -464,7 +480,7 @@
module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
module.Module.properties.Installable = proptools.BoolPtr(true)
- module.appProperties.EmbedJNI = true
+ module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
module.AddProperties(
diff --git a/java/app_builder.go b/java/app_builder.go
index 5b999d8..6cc2159 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -200,14 +200,14 @@
}
func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.WritablePath,
- jniLibs []jniLib) {
+ jniLibs []jniLib, uncompressJNI bool) {
var deps android.Paths
jarArgs := []string{
"-j", // junk paths, they will be added back with -P arguments
}
- if !ctx.Config().UnbundledBuild() {
+ if uncompressJNI {
jarArgs = append(jarArgs, "-L 0")
}
diff --git a/java/app_test.go b/java/app_test.go
index 93d20d0..103f24b 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -106,6 +106,64 @@
}
}
+func TestResourceDirs(t *testing.T) {
+ testCases := []struct {
+ name string
+ prop string
+ resources []string
+ }{
+ {
+ name: "no resource_dirs",
+ prop: "",
+ resources: []string{"res/res/values/strings.xml"},
+ },
+ {
+ name: "resource_dirs",
+ prop: `resource_dirs: ["res"]`,
+ resources: []string{"res/res/values/strings.xml"},
+ },
+ {
+ name: "empty resource_dirs",
+ prop: `resource_dirs: []`,
+ resources: nil,
+ },
+ }
+
+ fs := map[string][]byte{
+ "res/res/values/strings.xml": nil,
+ }
+
+ bp := `
+ android_app {
+ name: "foo",
+ %s
+ }
+ `
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ config := testConfig(nil)
+ ctx := testContext(config, fmt.Sprintf(bp, testCase.prop), fs)
+ run(t, ctx, config)
+
+ module := ctx.ModuleForTests("foo", "android_common")
+ resourceList := module.MaybeOutput("aapt2/res.list")
+
+ var resources []string
+ if resourceList.Rule != nil {
+ for _, compiledResource := range resourceList.Inputs.Strings() {
+ resources = append(resources, module.Output(compiledResource).Inputs.Strings()...)
+ }
+ }
+
+ if !reflect.DeepEqual(resources, testCase.resources) {
+ t.Errorf("expected resource files %q, got %q",
+ testCase.resources, resources)
+ }
+ })
+ }
+}
+
func TestEnforceRRO(t *testing.T) {
testCases := []struct {
name string
diff --git a/java/builder.go b/java/builder.go
index 7aac881..aa61a85 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -122,8 +122,8 @@
zipalign = pctx.AndroidStaticRule("zipalign",
blueprint.RuleParams{
- Command: "if ! ${config.ZipAlign} -c 4 $in > /dev/null; then " +
- "${config.ZipAlign} -f 4 $in $out; " +
+ Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
+ "${config.ZipAlign} -f -p 4 $in $out; " +
"else " +
"cp -f $in $out; " +
"fi",
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 33c46f4..55662cf 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -149,7 +149,6 @@
DexLocation: dexLocation,
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").String(),
DexPath: dexJarFile.String(),
- UseEmbeddedDex: false,
UncompressedDex: d.uncompressedDex,
HasApkLibraries: false,
PreoptFlags: nil,
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 96de755..de1bcf5 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -283,7 +283,7 @@
// Both paths are used to call dist-for-goals.
func hiddenAPIMakeVars(ctx android.MakeVarsContext) {
if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
- singletonPaths := ctx.Config().Get(hiddenAPISingletonPathsKey).(hiddenAPISingletonPathsStruct)
+ singletonPaths := hiddenAPISingletonPaths(ctx)
ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", singletonPaths.flags.String())
ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", singletonPaths.metadata.String())
}
diff --git a/java/java.go b/java/java.go
index 22829e4..3d7d6ad 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1423,6 +1423,11 @@
android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
return true
}
+ if ctx.Config().UncompressPrivAppDex() &&
+ inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules()) {
+ return true
+ }
+
return false
}
diff --git a/java/support_libraries.go b/java/support_libraries.go
index 320afae..5a72f41 100644
--- a/java/support_libraries.go
+++ b/java/support_libraries.go
@@ -28,9 +28,8 @@
func supportLibrariesMakeVarsProvider(ctx android.MakeVarsContext) {
var supportAars, supportJars []string
- sctx := ctx.SingletonContext()
- sctx.VisitAllModules(func(module android.Module) {
- dir := sctx.ModuleDir(module)
+ ctx.VisitAllModules(func(module android.Module) {
+ dir := ctx.ModuleDir(module)
switch {
case strings.HasPrefix(dir, "prebuilts/sdk/current/extras"),
dir == "prebuilts/sdk/current/androidx",
@@ -43,7 +42,7 @@
return
}
- name := sctx.ModuleName(module)
+ name := ctx.ModuleName(module)
if strings.HasSuffix(name, "-nodeps") {
return
}
@@ -54,7 +53,7 @@
case *Library, *Import:
supportJars = append(supportJars, name)
default:
- sctx.ModuleErrorf(module, "unknown module type %t", module)
+ ctx.ModuleErrorf(module, "unknown module type %t", module)
}
})
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 917f55b..83868e6 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -63,8 +63,12 @@
help='manifest is for a package built against the platform')
parser.add_argument('--use-embedded-dex', dest='use_embedded_dex', action='store_true',
help=('specify if the app wants to use embedded dex and avoid extracted,'
- 'locally compiled code. Should not be conflict if already declared '
+ 'locally compiled code. Must not conflict if already declared '
'in the manifest.'))
+ parser.add_argument('--extract-native-libs', dest='extract_native_libs',
+ default=None, type=lambda x: (str(x).lower() == 'true'),
+ help=('specify if the app wants to use embedded native libraries. Must not conflict '
+ 'if already declared in the manifest.'))
parser.add_argument('input', help='input AndroidManifest.xml file')
parser.add_argument('output', help='output AndroidManifest.xml file')
return parser.parse_args()
@@ -295,6 +299,30 @@
raise RuntimeError('existing attribute mismatches the option of --use-embedded-dex')
+def add_extract_native_libs(doc, extract_native_libs):
+ manifest = parse_manifest(doc)
+ elems = get_children_with_tag(manifest, 'application')
+ application = elems[0] if len(elems) == 1 else None
+ if len(elems) > 1:
+ raise RuntimeError('found multiple <application> tags')
+ elif not elems:
+ application = doc.createElement('application')
+ indent = get_indent(manifest.firstChild, 1)
+ first = manifest.firstChild
+ manifest.insertBefore(doc.createTextNode(indent), first)
+ manifest.insertBefore(application, first)
+
+ value = str(extract_native_libs).lower()
+ attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs')
+ if attr is None:
+ attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs')
+ attr.value = value
+ application.setAttributeNode(attr)
+ elif attr.value != value:
+ raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' %
+ (attr.value, value))
+
+
def write_xml(f, doc):
f.write('<?xml version="1.0" encoding="utf-8"?>\n')
for node in doc.childNodes:
@@ -325,6 +353,9 @@
if args.use_embedded_dex:
add_use_embedded_dex(doc)
+ if args.extract_native_libs is not None:
+ add_extract_native_libs(doc, args.extract_native_libs)
+
with open(args.output, 'wb') as f:
write_xml(f, doc)
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 1d8de55..4ad9afa 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -381,5 +381,48 @@
manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
self.assertRaises(RuntimeError, self.run_test, manifest_input)
+
+class AddExtractNativeLibsTest(unittest.TestCase):
+ """Unit tests for add_extract_native_libs function."""
+
+ def run_test(self, input_manifest, value):
+ doc = minidom.parseString(input_manifest)
+ manifest_fixer.add_extract_native_libs(doc, value)
+ output = StringIO.StringIO()
+ manifest_fixer.write_xml(output, doc)
+ return output.getvalue()
+
+ manifest_tmpl = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ ' <application%s/>\n'
+ '</manifest>\n')
+
+ def extract_native_libs(self, value):
+ return ' android:extractNativeLibs="%s"' % value
+
+ def test_set_true(self):
+ manifest_input = self.manifest_tmpl % ''
+ expected = self.manifest_tmpl % self.extract_native_libs('true')
+ output = self.run_test(manifest_input, True)
+ self.assertEqual(output, expected)
+
+ def test_set_false(self):
+ manifest_input = self.manifest_tmpl % ''
+ expected = self.manifest_tmpl % self.extract_native_libs('false')
+ output = self.run_test(manifest_input, False)
+ self.assertEqual(output, expected)
+
+ def test_match(self):
+ manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
+ expected = manifest_input
+ output = self.run_test(manifest_input, True)
+ self.assertEqual(output, expected)
+
+ def test_conflict(self):
+ manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
+ self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 98bb1c5..d644f5f 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -214,11 +214,13 @@
ctx.Fatalln("Error dumping make vars:", err)
}
+ env := config.Environment()
// Print the banner like make does
- ctx.Writer.Print(Banner(make_vars))
+ if !env.IsEnvTrue("ANDROID_QUIET_BUILD") {
+ ctx.Writer.Print(Banner(make_vars))
+ }
// Populate the environment
- env := config.Environment()
for _, name := range exportEnvVars {
if make_vars[name] == "" {
env.Unset(name)
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index c8eb382..2445c5b 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -27,6 +27,7 @@
format string
start time.Time
+ quiet bool
}
// NewStatusOutput returns a StatusOutput that represents the
@@ -35,12 +36,13 @@
//
// statusFormat takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported.
-func NewStatusOutput(w Writer, statusFormat string) status.StatusOutput {
+func NewStatusOutput(w Writer, statusFormat string, quietBuild bool) status.StatusOutput {
return &statusOutput{
writer: w,
format: statusFormat,
start: time.Now(),
+ quiet: quietBuild,
}
}
@@ -76,13 +78,12 @@
progress := s.progress(counts) + str
if result.Error != nil {
- hasCommand := ""
- if result.Command != "" {
- hasCommand = "\n"
+ targets := strings.Join(result.Outputs, " ")
+ if s.quiet || result.Command == "" {
+ s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s", targets, result.Output))
+ } else {
+ s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s\n%s", targets, result.Command, result.Output))
}
-
- s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s%s%s",
- strings.Join(result.Outputs, " "), result.Command, hasCommand, result.Output))
} else if result.Output != "" {
s.writer.StatusAndMessage(progress, result.Output)
} else {