Merge changes I918b4878,I85238d93,Iefee8a91
* changes:
Add an output file tag for proguard dictionaries
Add InstallBypassMake
Document wokaround for yama ptrace restrictions
diff --git a/Android.bp b/Android.bp
index 62b0fd4..4e44a0d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -282,6 +282,7 @@
"java/jdeps.go",
"java/java_resources.go",
"java/kotlin.go",
+ "java/platform_compat_config.go",
"java/plugin.go",
"java/prebuilt_apis.go",
"java/proto.go",
diff --git a/android/neverallow.go b/android/neverallow.go
index 23b6454..8355bb3 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -175,6 +175,8 @@
dir := ctx.ModuleDir() + "/"
properties := m.GetProperties()
+ osClass := ctx.Module().Target().Os.Class
+
for _, r := range neverallows {
n := r.(*rule)
if !n.appliesToPath(dir) {
@@ -189,6 +191,14 @@
continue
}
+ if !n.appliesToOsClass(osClass) {
+ continue
+ }
+
+ if !n.appliesToDirectDeps(ctx) {
+ continue
+ }
+
ctx.ModuleErrorf("violates " + n.String())
}
}
@@ -246,6 +256,10 @@
NotIn(path ...string) Rule
+ InDirectDeps(deps ...string) Rule
+
+ WithOsClass(osClasses ...OsClass) Rule
+
ModuleType(types ...string) Rule
NotModuleType(types ...string) Rule
@@ -268,6 +282,10 @@
paths []string
unlessPaths []string
+ directDeps map[string]bool
+
+ osClasses []OsClass
+
moduleTypes []string
unlessModuleTypes []string
@@ -277,7 +295,7 @@
// Create a new NeverAllow rule.
func NeverAllow() Rule {
- return &rule{}
+ return &rule{directDeps: make(map[string]bool)}
}
func (r *rule) In(path ...string) Rule {
@@ -290,6 +308,18 @@
return r
}
+func (r *rule) InDirectDeps(deps ...string) Rule {
+ for _, d := range deps {
+ r.directDeps[d] = true
+ }
+ return r
+}
+
+func (r *rule) WithOsClass(osClasses ...OsClass) Rule {
+ r.osClasses = append(r.osClasses, osClasses...)
+ return r
+}
+
func (r *rule) ModuleType(types ...string) Rule {
r.moduleTypes = append(r.moduleTypes, types...)
return r
@@ -356,6 +386,12 @@
for _, v := range r.unlessProps {
s += " -" + strings.Join(v.fields, ".") + v.matcher.String()
}
+ for k := range r.directDeps {
+ s += " deps:" + k
+ }
+ for _, v := range r.osClasses {
+ s += " os:" + v.String()
+ }
if len(r.reason) != 0 {
s += " which is restricted because " + r.reason
}
@@ -368,6 +404,36 @@
return includePath && !excludePath
}
+func (r *rule) appliesToDirectDeps(ctx BottomUpMutatorContext) bool {
+ if len(r.directDeps) == 0 {
+ return true
+ }
+
+ matches := false
+ ctx.VisitDirectDeps(func(m Module) {
+ if !matches {
+ name := ctx.OtherModuleName(m)
+ matches = r.directDeps[name]
+ }
+ })
+
+ return matches
+}
+
+func (r *rule) appliesToOsClass(osClass OsClass) bool {
+ if len(r.osClasses) == 0 {
+ return true
+ }
+
+ for _, c := range r.osClasses {
+ if c == osClass {
+ return true
+ }
+ }
+
+ return false
+}
+
func (r *rule) appliesToModuleType(moduleType string) bool {
return (len(r.moduleTypes) == 0 || InList(moduleType, r.moduleTypes)) && !InList(moduleType, r.unlessModuleTypes)
}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 02b4362..920b9a5 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -16,13 +16,43 @@
import (
"testing"
+
+ "github.com/google/blueprint"
)
+func init() {
+ // Add extra rules needed for testing.
+ AddNeverAllowRules(
+ NeverAllow().InDirectDeps("not_allowed_in_direct_deps"),
+ )
+}
+
var neverallowTests = []struct {
name string
fs map[string][]byte
expectedError string
}{
+ // Test General Functionality
+
+ // in direct deps tests
+ {
+ name: "not_allowed_in_direct_deps",
+ fs: map[string][]byte{
+ "top/Blueprints": []byte(`
+ cc_library {
+ name: "not_allowed_in_direct_deps",
+ }`),
+ "other/Blueprints": []byte(`
+ cc_library {
+ name: "libother",
+ static_libs: ["not_allowed_in_direct_deps"],
+ }`),
+ },
+ expectedError: `module "libother": violates neverallow deps:not_allowed_in_direct_deps`,
+ },
+
+ // Test specific rules
+
// include_dir rule tests
{
name: "include_dir not allowed to reference art",
@@ -242,6 +272,7 @@
type mockCcLibraryProperties struct {
Include_dirs []string
Vendor_available *bool
+ Static_libs []string
Vndk struct {
Enabled *bool
@@ -272,6 +303,19 @@
return m
}
+type neverallowTestDependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
+var staticDepTag = neverallowTestDependencyTag{name: "static"}
+
+func (c *mockCcLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
+ for _, lib := range c.properties.Static_libs {
+ ctx.AddDependency(ctx.Module(), staticDepTag, lib)
+ }
+}
+
func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
diff --git a/android/util.go b/android/util.go
index 97bec10..e02cca1 100644
--- a/android/util.go
+++ b/android/util.go
@@ -199,6 +199,13 @@
return list[totalSkip:]
}
+// SortedUniqueStrings returns what the name says
+func SortedUniqueStrings(list []string) []string {
+ unique := FirstUniqueStrings(list)
+ sort.Strings(unique)
+ return unique
+}
+
// checkCalledFromInit panics if a Go package's init function is not on the
// call stack.
func checkCalledFromInit() {
diff --git a/android/variable.go b/android/variable.go
index e9379b7..bfff81c 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -59,17 +59,6 @@
Cflags []string
}
- // Product_is_iot is true for Android Things devices.
- Product_is_iot struct {
- Cflags []string
- Enabled bool
- Exclude_srcs []string
- Init_rc []string
- Shared_libs []string
- Srcs []string
- Static_libs []string
- }
-
// treble_linker_namespaces is true when the system/vendor linker namespace separation is
// enabled.
Treble_linker_namespaces struct {
@@ -262,8 +251,6 @@
Override_rs_driver *string `json:",omitempty"`
- Product_is_iot *bool `json:",omitempty"`
-
Fuchsia *bool `json:",omitempty"`
DeviceKernelHeaders []string `json:",omitempty"`
diff --git a/apex/TEST_MAPPING b/apex/TEST_MAPPING
new file mode 100644
index 0000000..d0223d1
--- /dev/null
+++ b/apex/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "system/apex/apexd"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apex/apex.go b/apex/apex.go
index 441911b..e4fad83 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -46,13 +46,21 @@
Description: "fs_config ${out}",
}, "ro_paths", "exec_paths")
+ injectApexDependency = pctx.StaticRule("injectApexDependency", blueprint.RuleParams{
+ Command: `rm -f $out && ${jsonmodify} $in ` +
+ `-a provideNativeLibs ${provideNativeLibs} ` +
+ `-a requireNativeLibs ${requireNativeLibs} -o $out`,
+ CommandDeps: []string{"${jsonmodify}"},
+ Description: "Inject dependency into ${out}",
+ }, "provideNativeLibs", "requireNativeLibs")
+
// TODO(b/113233103): make sure that file_contexts is sane, i.e., validate
// against the binary policy using sefcontext_compiler -p <policy>.
// TODO(b/114327326): automate the generation of file_contexts
apexRule = pctx.StaticRule("apexRule", blueprint.RuleParams{
Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
- `(${copy_commands}) && ` +
+ `(. ${out}.copy_commands) && ` +
`APEXER_TOOL_PATH=${tool_path} ` +
`${apexer} --force --manifest ${manifest} ` +
`--file_contexts ${file_contexts} ` +
@@ -62,18 +70,22 @@
CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
"${mke2fs}", "${resize2fs}", "${sefcontext_compile}",
"${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
- Description: "APEX ${image_dir} => ${out}",
+ Rspfile: "${out}.copy_commands",
+ RspfileContent: "${copy_commands}",
+ Description: "APEX ${image_dir} => ${out}",
}, "tool_path", "image_dir", "copy_commands", "manifest", "file_contexts", "canned_fs_config", "key", "opt_flags")
zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
- `(${copy_commands}) && ` +
+ `(. ${out}.copy_commands) && ` +
`APEXER_TOOL_PATH=${tool_path} ` +
`${apexer} --force --manifest ${manifest} ` +
`--payload_type zip ` +
`${image_dir} ${out} `,
- CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
- Description: "ZipAPEX ${image_dir} => ${out}",
+ CommandDeps: []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
+ Rspfile: "${out}.copy_commands",
+ RspfileContent: "${copy_commands}",
+ Description: "ZipAPEX ${image_dir} => ${out}",
}, "tool_path", "image_dir", "copy_commands", "manifest")
apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
@@ -139,6 +151,7 @@
pctx.HostBinToolVariable("soong_zip", "soong_zip")
pctx.HostBinToolVariable("zip2zip", "zip2zip")
pctx.HostBinToolVariable("zipalign", "zipalign")
+ pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
android.RegisterModuleType("apex", apexBundleFactory)
android.RegisterModuleType("apex_test", testApexBundleFactory)
@@ -427,6 +440,9 @@
flattened bool
testApex bool
+
+ // intermediate path for apex_manifest.json
+ manifestOut android.WritablePath
}
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -751,6 +767,10 @@
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
+ // native lib dependencies
+ var provideNativeLibs []string
+ var requireNativeLibs []string
+
// Check if "uses" requirements are met with dependent apexBundles
var providedNativeSharedLibs []string
useVendor := proptools.Bool(a.properties.Use_vendor)
@@ -783,6 +803,9 @@
switch depTag {
case sharedLibTag:
if cc, ok := child.(*cc.Module); ok {
+ if cc.HasStubsVariants() {
+ provideNativeLibs = append(provideNativeLibs, cc.OutputFile().Path().Base())
+ }
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc, handleSpecialLibs)
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeSharedLib, cc, nil})
return true
@@ -894,6 +917,7 @@
if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.externalDeps) {
a.externalDeps = append(a.externalDeps, cc.Name())
}
+ requireNativeLibs = append(requireNativeLibs, cc.OutputFile().Path().Base())
// Don't track further
return false
}
@@ -954,6 +978,21 @@
a.installDir = android.PathForModuleInstall(ctx, "apex")
a.filesInfo = filesInfo
+ a.manifestOut = android.PathForModuleOut(ctx, "apex_manifest.json")
+ // put dependency({provide|require}NativeLibs) in apex_manifest.json
+ manifestSrc := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
+ provideNativeLibs = android.SortedUniqueStrings(provideNativeLibs)
+ requireNativeLibs = android.SortedUniqueStrings(android.RemoveListFromList(requireNativeLibs, provideNativeLibs))
+ ctx.Build(pctx, android.BuildParams{
+ Rule: injectApexDependency,
+ Input: manifestSrc,
+ Output: a.manifestOut,
+ Args: map[string]string{
+ "provideNativeLibs": strings.Join(provideNativeLibs, " "),
+ "requireNativeLibs": strings.Join(requireNativeLibs, " "),
+ },
+ })
+
if a.apexTypes.zip() {
a.buildUnflattenedApex(ctx, zipApex)
}
@@ -1001,8 +1040,6 @@
a.container_private_key_file = key
}
- manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-
var abis []string
for _, target := range ctx.MultiTargets() {
if len(target.Arch.Abi) > 0 {
@@ -1032,7 +1069,7 @@
}
}
implicitInputs := append(android.Paths(nil), filesToCopy...)
- implicitInputs = append(implicitInputs, manifest)
+ implicitInputs = append(implicitInputs, a.manifestOut)
outHostBinDir := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin").String()
prebuiltSdkToolsBinDir := filepath.Join("prebuilts", "sdk", "tools", runtime.GOOS, "bin")
@@ -1127,7 +1164,7 @@
"tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
"image_dir": android.PathForModuleOut(ctx, "image"+suffix).String(),
"copy_commands": strings.Join(copyCommands, " && "),
- "manifest": manifest.String(),
+ "manifest": a.manifestOut.String(),
"file_contexts": fileContexts.String(),
"canned_fs_config": cannedFsConfig.String(),
"key": a.private_key_file.String(),
@@ -1165,7 +1202,7 @@
"tool_path": outHostBinDir + ":" + prebuiltSdkToolsBinDir,
"image_dir": android.PathForModuleOut(ctx, "image"+suffix).String(),
"copy_commands": strings.Join(copyCommands, " && "),
- "manifest": manifest.String(),
+ "manifest": a.manifestOut.String(),
},
})
}
@@ -1196,16 +1233,7 @@
if a.installable() {
// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
// with other ordinary files.
- manifest := android.PathForModuleSrc(ctx, proptools.StringDefault(a.properties.Manifest, "apex_manifest.json"))
-
- // rename to apex_manifest.json
- copiedManifest := android.PathForModuleOut(ctx, "apex_manifest.json")
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Cp,
- Input: manifest,
- Output: copiedManifest,
- })
- a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
+ a.filesInfo = append(a.filesInfo, apexFile{a.manifestOut, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
// rename to apex_pubkey
copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
@@ -1493,6 +1521,10 @@
// to build the prebuilts themselves.
forceDisable = forceDisable || ctx.Config().UnbundledBuild()
+ // Force disable the prebuilts when coverage is enabled.
+ forceDisable = forceDisable || ctx.DeviceConfig().NativeCoverageEnabled()
+ forceDisable = forceDisable || ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
+
// b/137216042 don't use prebuilts when address sanitizer is on
forceDisable = forceDisable || android.InList("address", ctx.Config().SanitizeDevice()) ||
android.InList("hwaddress", ctx.Config().SanitizeDevice())
diff --git a/apex/apex_test.go b/apex/apex_test.go
index cecdaaf..38d2bf2 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -270,6 +270,13 @@
}
}
+func ensureListEmpty(t *testing.T, result []string) {
+ t.Helper()
+ if len(result) > 0 {
+ t.Errorf("%q is expected to be empty", result)
+ }
+}
+
// Minimal test
func TestBasicApex(t *testing.T) {
ctx, _ := testApex(t, `
@@ -1060,6 +1067,109 @@
ensureContains(t, cFlags, "-Imy_include")
}
+func TestDependenciesInApexManifest(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex_nodep",
+ key: "myapex.key",
+ native_shared_libs: ["lib_nodep"],
+ compile_multilib: "both",
+ file_contexts: "myapex",
+ }
+
+ apex {
+ name: "myapex_dep",
+ key: "myapex.key",
+ native_shared_libs: ["lib_dep"],
+ compile_multilib: "both",
+ file_contexts: "myapex",
+ }
+
+ apex {
+ name: "myapex_provider",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ compile_multilib: "both",
+ file_contexts: "myapex",
+ }
+
+ apex {
+ name: "myapex_selfcontained",
+ key: "myapex.key",
+ native_shared_libs: ["lib_dep", "libfoo"],
+ compile_multilib: "both",
+ file_contexts: "myapex",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "lib_nodep",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "lib_dep",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libfoo"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libfoo",
+ srcs: ["mytest.cpp"],
+ stubs: {
+ versions: ["1"],
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ names := func(s string) (ns []string) {
+ for _, n := range strings.Split(s, " ") {
+ if len(n) > 0 {
+ ns = append(ns, n)
+ }
+ }
+ return
+ }
+
+ var injectRule android.TestingBuildParams
+ var provideNativeLibs, requireNativeLibs []string
+
+ injectRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("injectApexDependency")
+ provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+ requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+ ensureListEmpty(t, provideNativeLibs)
+ ensureListEmpty(t, requireNativeLibs)
+
+ injectRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("injectApexDependency")
+ provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+ requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+ ensureListEmpty(t, provideNativeLibs)
+ ensureListContains(t, requireNativeLibs, "libfoo.so")
+
+ injectRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("injectApexDependency")
+ provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+ requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+ ensureListContains(t, provideNativeLibs, "libfoo.so")
+ ensureListEmpty(t, requireNativeLibs)
+
+ injectRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("injectApexDependency")
+ provideNativeLibs = names(injectRule.Args["provideNativeLibs"])
+ requireNativeLibs = names(injectRule.Args["requireNativeLibs"])
+ ensureListContains(t, provideNativeLibs, "libfoo.so")
+ ensureListEmpty(t, requireNativeLibs)
+}
+
func TestNonTestApex(t *testing.T) {
ctx, _ := testApex(t, `
apex {
diff --git a/cc/cc.go b/cc/cc.go
index cc2e65f..2bde2d3 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -267,7 +267,7 @@
isVndkSp() bool
isVndkExt() bool
inRecovery() bool
- shouldCreateVndkSourceAbiDump(config android.Config) bool
+ shouldCreateSourceAbiDump() bool
selectedStl() string
baseModuleName() string
getVndkExtendsModuleName() string
@@ -789,7 +789,7 @@
}
// Check whether ABI dumps should be created for this module.
-func (ctx *moduleContextImpl) shouldCreateVndkSourceAbiDump(config android.Config) bool {
+func (ctx *moduleContextImpl) shouldCreateSourceAbiDump() bool {
if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
return false
}
@@ -815,18 +815,7 @@
// Stubs do not need ABI dumps.
return false
}
- if ctx.isNdk() {
- return true
- }
- if ctx.isLlndkPublic(config) {
- return true
- }
- if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(config) {
- // Return true if this is VNDK-core, VNDK-SP, or VNDK-Ext and this is not
- // VNDK-private.
- return true
- }
- return false
+ return true
}
func (ctx *moduleContextImpl) selectedStl() string {
@@ -1898,7 +1887,7 @@
isVendorPublicLib := inList(libName, *vendorPublicLibraries)
bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk
- if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() {
+ if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.isVndk() && !ccDep.mustUseVendorVariant() && !c.inRecovery() {
// The vendor module is a no-vendor-variant VNDK library. Depend on the
// core module instead.
return libName
diff --git a/cc/compiler.go b/cc/compiler.go
index ffb6ad2..85ff400 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -309,6 +309,7 @@
flags.SystemIncludeFlags = append(flags.SystemIncludeFlags,
"-isystem "+getCurrentIncludePath(ctx).String(),
"-isystem "+getCurrentIncludePath(ctx).Join(ctx, config.NDKTriple(tc)).String())
+ flags.GlobalFlags = append(flags.GlobalFlags, "-D__ANDROID_NDK__")
}
if ctx.useVndk() {
diff --git a/cc/config/global.go b/cc/config/global.go
index a27246e..9ce6896 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -150,8 +150,22 @@
pctx.StaticVariable("HostGlobalLdflags", strings.Join(hostGlobalLdflags, " "))
pctx.StaticVariable("HostGlobalLldflags", strings.Join(hostGlobalLldflags, " "))
- pctx.StaticVariable("CommonClangGlobalCflags",
- strings.Join(append(ClangFilterUnknownCflags(commonGlobalCflags), "${ClangExtraCflags}"), " "))
+ pctx.VariableFunc("CommonClangGlobalCflags", func(ctx android.PackageVarContext) string {
+ flags := ClangFilterUnknownCflags(commonGlobalCflags)
+ flags = append(flags, "${ClangExtraCflags}")
+
+ // http://b/131390872
+ // Automatically initialize any uninitialized stack variables.
+ // Prefer zero-init if both options are set.
+ if ctx.Config().IsEnvTrue("AUTO_ZERO_INITIALIZE") {
+ flags = append(flags, "-ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang")
+ } else if ctx.Config().IsEnvTrue("AUTO_PATTERN_INITIALIZE") {
+ flags = append(flags, "-ftrivial-auto-var-init=pattern")
+ }
+
+ return strings.Join(flags, " ")
+ })
+
pctx.VariableFunc("DeviceClangGlobalCflags", func(ctx android.PackageVarContext) string {
if ctx.Config().Fuchsia() {
return strings.Join(ClangFilterUnknownCflags(deviceGlobalCflags), " ")
diff --git a/cc/library.go b/cc/library.go
index 2b7c9a1..b193ab7 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -432,11 +432,25 @@
return flags
}
-func (library *libraryDecorator) shouldCreateVndkSourceAbiDump(ctx ModuleContext) bool {
+func (library *libraryDecorator) shouldCreateSourceAbiDump(ctx ModuleContext) bool {
+ if !ctx.shouldCreateSourceAbiDump() {
+ return false
+ }
if library.Properties.Header_abi_checker.Enabled != nil {
return Bool(library.Properties.Header_abi_checker.Enabled)
}
- return ctx.shouldCreateVndkSourceAbiDump(ctx.Config())
+ if ctx.isNdk() {
+ return true
+ }
+ if ctx.isLlndkPublic(ctx.Config()) {
+ return true
+ }
+ if ctx.useVndk() && ctx.isVndk() && !ctx.isVndkPrivate(ctx.Config()) {
+ // Return true if this is VNDK-core, VNDK-SP, or VNDK-Ext, and not
+ // VNDK-private.
+ return true
+ }
+ return false
}
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
@@ -458,7 +472,7 @@
}
return Objects{}
}
- if library.shouldCreateVndkSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps {
+ if library.shouldCreateSourceAbiDump(ctx) || library.sabi.Properties.CreateSAbiDumps {
exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
var SourceAbiFlags []string
for _, dir := range exportIncludeDirs.Strings() {
@@ -822,7 +836,7 @@
}
func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
- if library.shouldCreateVndkSourceAbiDump(ctx) {
+ if library.shouldCreateSourceAbiDump(ctx) {
vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
if ver := ctx.DeviceConfig().VndkVersion(); ver != "" && ver != "current" {
vndkVersion = ver
diff --git a/cc/linker.go b/cc/linker.go
index daacec1..962fcce 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -125,6 +125,10 @@
// variant of the C/C++ module.
Shared_libs []string
+ // list of static libs that only should be used to build the recovery
+ // variant of the C/C++ module.
+ Static_libs []string
+
// list of shared libs that should not be used to build
// the recovery variant of the C/C++ module.
Exclude_shared_libs []string
@@ -211,6 +215,7 @@
deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Recovery.Shared_libs...)
deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Recovery.Exclude_shared_libs)
deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Recovery.Exclude_shared_libs)
+ deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Recovery.Static_libs...)
deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
deps.HeaderLibs = removeListFromList(deps.HeaderLibs, linker.Properties.Target.Recovery.Exclude_header_libs)
deps.ReexportHeaderLibHeaders = removeListFromList(deps.ReexportHeaderLibHeaders, linker.Properties.Target.Recovery.Exclude_header_libs)
diff --git a/cc/lto.go b/cc/lto.go
index 1084869..431d70d 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -80,6 +80,12 @@
}
func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags {
+ // TODO(b/131771163): Disable LTO when using explicit fuzzing configurations.
+ // LTO breaks fuzzer builds.
+ if inList("-fsanitize=fuzzer-no-link", flags.CFlags) {
+ return flags
+ }
+
if lto.LTO() {
var ltoFlag string
if Bool(lto.Properties.Lto.Thin) {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 969cb3f..3747b41 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -54,6 +54,7 @@
"mediandk",
"nativewindow",
"m",
+ "neuralnetworks",
"OpenMAXAL",
"OpenSLES",
"stdc++",
diff --git a/cc/sanitize.go b/cc/sanitize.go
index b238b7e..261ca88 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -464,7 +464,9 @@
// TODO(b/131771163): LTO and Fuzzer support is mutually incompatible.
_, flags.LdFlags = removeFromList("-flto", flags.LdFlags)
+ _, flags.CFlags = removeFromList("-flto", flags.CFlags)
flags.LdFlags = append(flags.LdFlags, "-fno-lto")
+ flags.CFlags = append(flags.CFlags, "-fno-lto")
// TODO(b/133876586): Experimental PM breaks sanitizer coverage.
_, flags.CFlags = removeFromList("-fexperimental-new-pass-manager", flags.CFlags)
diff --git a/cmd/merge_zips/Android.bp b/cmd/merge_zips/Android.bp
index ab658fd..f70c86e 100644
--- a/cmd/merge_zips/Android.bp
+++ b/cmd/merge_zips/Android.bp
@@ -18,6 +18,7 @@
"android-archive-zip",
"blueprint-pathtools",
"soong-jar",
+ "soong-zip",
],
srcs: [
"merge_zips.go",
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index 68fe259..27179cb 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -30,8 +30,566 @@
"android/soong/jar"
"android/soong/third_party/zip"
+ soongZip "android/soong/zip"
)
+// Input zip: we can open it, close it, and obtain an array of entries
+type InputZip interface {
+ Name() string
+ Open() error
+ Close() error
+ Entries() []*zip.File
+ IsOpen() bool
+}
+
+// An entry that can be written to the output zip
+type ZipEntryContents interface {
+ String() string
+ IsDir() bool
+ CRC32() uint32
+ Size() uint64
+ WriteToZip(dest string, zw *zip.Writer) error
+}
+
+// a ZipEntryFromZip is a ZipEntryContents that pulls its content from another zip
+// identified by the input zip and the index of the entry in its entries array
+type ZipEntryFromZip struct {
+ inputZip InputZip
+ index int
+ name string
+ isDir bool
+ crc32 uint32
+ size uint64
+}
+
+func NewZipEntryFromZip(inputZip InputZip, entryIndex int) *ZipEntryFromZip {
+ fi := inputZip.Entries()[entryIndex]
+ newEntry := ZipEntryFromZip{inputZip: inputZip,
+ index: entryIndex,
+ name: fi.Name,
+ isDir: fi.FileInfo().IsDir(),
+ crc32: fi.CRC32,
+ size: fi.UncompressedSize64,
+ }
+ return &newEntry
+}
+
+func (ze ZipEntryFromZip) String() string {
+ return fmt.Sprintf("%s!%s", ze.inputZip.Name(), ze.name)
+}
+
+func (ze ZipEntryFromZip) IsDir() bool {
+ return ze.isDir
+}
+
+func (ze ZipEntryFromZip) CRC32() uint32 {
+ return ze.crc32
+}
+
+func (ze ZipEntryFromZip) Size() uint64 {
+ return ze.size
+}
+
+func (ze ZipEntryFromZip) WriteToZip(dest string, zw *zip.Writer) error {
+ if err := ze.inputZip.Open(); err != nil {
+ return err
+ }
+ return zw.CopyFrom(ze.inputZip.Entries()[ze.index], dest)
+}
+
+// a ZipEntryFromBuffer is a ZipEntryContents that pulls its content from a []byte
+type ZipEntryFromBuffer struct {
+ fh *zip.FileHeader
+ content []byte
+}
+
+func (be ZipEntryFromBuffer) String() string {
+ return "internal buffer"
+}
+
+func (be ZipEntryFromBuffer) IsDir() bool {
+ return be.fh.FileInfo().IsDir()
+}
+
+func (be ZipEntryFromBuffer) CRC32() uint32 {
+ return crc32.ChecksumIEEE(be.content)
+}
+
+func (be ZipEntryFromBuffer) Size() uint64 {
+ return uint64(len(be.content))
+}
+
+func (be ZipEntryFromBuffer) WriteToZip(dest string, zw *zip.Writer) error {
+ w, err := zw.CreateHeader(be.fh)
+ if err != nil {
+ return err
+ }
+
+ if !be.IsDir() {
+ _, err = w.Write(be.content)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+// Processing state.
+type OutputZip struct {
+ outputWriter *zip.Writer
+ stripDirEntries bool
+ emulateJar bool
+ sortEntries bool
+ ignoreDuplicates bool
+ excludeDirs []string
+ excludeFiles []string
+ sourceByDest map[string]ZipEntryContents
+}
+
+func NewOutputZip(outputWriter *zip.Writer, sortEntries, emulateJar, stripDirEntries, ignoreDuplicates bool) *OutputZip {
+ return &OutputZip{
+ outputWriter: outputWriter,
+ stripDirEntries: stripDirEntries,
+ emulateJar: emulateJar,
+ sortEntries: sortEntries,
+ sourceByDest: make(map[string]ZipEntryContents, 0),
+ ignoreDuplicates: ignoreDuplicates,
+ }
+}
+
+func (oz *OutputZip) setExcludeDirs(excludeDirs []string) {
+ oz.excludeDirs = make([]string, len(excludeDirs))
+ for i, dir := range excludeDirs {
+ oz.excludeDirs[i] = filepath.Clean(dir)
+ }
+}
+
+func (oz *OutputZip) setExcludeFiles(excludeFiles []string) {
+ oz.excludeFiles = excludeFiles
+}
+
+// Adds an entry with given name whose source is given ZipEntryContents. Returns old ZipEntryContents
+// if entry with given name already exists.
+func (oz *OutputZip) addZipEntry(name string, source ZipEntryContents) (ZipEntryContents, error) {
+ if existingSource, exists := oz.sourceByDest[name]; exists {
+ return existingSource, nil
+ }
+ oz.sourceByDest[name] = source
+ // Delay writing an entry if entries need to be rearranged.
+ if oz.emulateJar || oz.sortEntries {
+ return nil, nil
+ }
+ return nil, source.WriteToZip(name, oz.outputWriter)
+}
+
+// Adds an entry for the manifest (META-INF/MANIFEST.MF from the given file
+func (oz *OutputZip) addManifest(manifestPath string) error {
+ if !oz.stripDirEntries {
+ if _, err := oz.addZipEntry(jar.MetaDir, ZipEntryFromBuffer{jar.MetaDirFileHeader(), nil}); err != nil {
+ return err
+ }
+ }
+ contents, err := ioutil.ReadFile(manifestPath)
+ if err == nil {
+ fh, buf, err := jar.ManifestFileContents(contents)
+ if err == nil {
+ _, err = oz.addZipEntry(jar.ManifestFile, ZipEntryFromBuffer{fh, buf})
+ }
+ }
+ return err
+}
+
+// Adds an entry with given name and contents read from given file
+func (oz *OutputZip) addZipEntryFromFile(name string, path string) error {
+ buf, err := ioutil.ReadFile(path)
+ if err == nil {
+ fh := &zip.FileHeader{
+ Name: name,
+ Method: zip.Store,
+ UncompressedSize64: uint64(len(buf)),
+ }
+ fh.SetMode(0700)
+ fh.SetModTime(jar.DefaultTime)
+ _, err = oz.addZipEntry(name, ZipEntryFromBuffer{fh, buf})
+ }
+ return err
+}
+
+func (oz *OutputZip) addEmptyEntry(entry string) error {
+ var emptyBuf []byte
+ fh := &zip.FileHeader{
+ Name: entry,
+ Method: zip.Store,
+ UncompressedSize64: uint64(len(emptyBuf)),
+ }
+ fh.SetMode(0700)
+ fh.SetModTime(jar.DefaultTime)
+ _, err := oz.addZipEntry(entry, ZipEntryFromBuffer{fh, emptyBuf})
+ return err
+}
+
+// Returns true if given entry is to be excluded
+func (oz *OutputZip) isEntryExcluded(name string) bool {
+ for _, dir := range oz.excludeDirs {
+ dir = filepath.Clean(dir)
+ patterns := []string{
+ dir + "/", // the directory itself
+ dir + "/**/*", // files recursively in the directory
+ dir + "/**/*/", // directories recursively in the directory
+ }
+
+ for _, pattern := range patterns {
+ match, err := pathtools.Match(pattern, name)
+ if err != nil {
+ panic(fmt.Errorf("%s: %s", err.Error(), pattern))
+ }
+ if match {
+ if oz.emulateJar {
+ // When merging jar files, don't strip META-INF/MANIFEST.MF even if stripping META-INF is
+ // requested.
+ // TODO(ccross): which files does this affect?
+ if name != jar.MetaDir && name != jar.ManifestFile {
+ return true
+ }
+ }
+ return true
+ }
+ }
+ }
+
+ for _, pattern := range oz.excludeFiles {
+ match, err := pathtools.Match(pattern, name)
+ if err != nil {
+ panic(fmt.Errorf("%s: %s", err.Error(), pattern))
+ }
+ if match {
+ return true
+ }
+ }
+ return false
+}
+
+// Creates a zip entry whose contents is an entry from the given input zip.
+func (oz *OutputZip) copyEntry(inputZip InputZip, index int) error {
+ entry := NewZipEntryFromZip(inputZip, index)
+ if oz.stripDirEntries && entry.IsDir() {
+ return nil
+ }
+ existingEntry, err := oz.addZipEntry(entry.name, entry)
+ if err != nil {
+ return err
+ }
+ if existingEntry == nil {
+ return nil
+ }
+
+ // File types should match
+ if existingEntry.IsDir() != entry.IsDir() {
+ return fmt.Errorf("Directory/file mismatch at %v from %v and %v\n",
+ entry.name, existingEntry, entry)
+ }
+
+ if oz.ignoreDuplicates ||
+ // Skip manifest and module info files that are not from the first input file
+ (oz.emulateJar && entry.name == jar.ManifestFile || entry.name == jar.ModuleInfoClass) ||
+ // Identical entries
+ (existingEntry.CRC32() == entry.CRC32() && existingEntry.Size() == entry.Size()) ||
+ // Directory entries
+ entry.IsDir() {
+ return nil
+ }
+
+ return fmt.Errorf("Duplicate path %v found in %v and %v\n", entry.name, existingEntry, inputZip.Name())
+}
+
+func (oz *OutputZip) entriesArray() []string {
+ entries := make([]string, len(oz.sourceByDest))
+ i := 0
+ for entry := range oz.sourceByDest {
+ entries[i] = entry
+ i++
+ }
+ return entries
+}
+
+func (oz *OutputZip) jarSorted() []string {
+ entries := oz.entriesArray()
+ sort.SliceStable(entries, func(i, j int) bool { return jar.EntryNamesLess(entries[i], entries[j]) })
+ return entries
+}
+
+func (oz *OutputZip) alphanumericSorted() []string {
+ entries := oz.entriesArray()
+ sort.Strings(entries)
+ return entries
+}
+
+func (oz *OutputZip) writeEntries(entries []string) error {
+ for _, entry := range entries {
+ source, _ := oz.sourceByDest[entry]
+ if err := source.WriteToZip(entry, oz.outputWriter); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (oz *OutputZip) getUninitializedPythonPackages(inputZips []InputZip) ([]string, error) {
+ // the runfiles packages needs to be populated with "__init__.py".
+ // the runfiles dirs have been treated as packages.
+ allPackages := make(map[string]bool)
+ initedPackages := make(map[string]bool)
+ getPackage := func(path string) string {
+ ret := filepath.Dir(path)
+ // filepath.Dir("abc") -> "." and filepath.Dir("/abc") -> "/".
+ if ret == "." || ret == "/" {
+ return ""
+ }
+ return ret
+ }
+
+ // put existing __init__.py files to a set first. This set is used for preventing
+ // generated __init__.py files from overwriting existing ones.
+ for _, inputZip := range inputZips {
+ if err := inputZip.Open(); err != nil {
+ return nil, err
+ }
+ for _, file := range inputZip.Entries() {
+ pyPkg := getPackage(file.Name)
+ if filepath.Base(file.Name) == "__init__.py" {
+ if _, found := initedPackages[pyPkg]; found {
+ panic(fmt.Errorf("found __init__.py path duplicates during pars merging: %q", file.Name))
+ }
+ initedPackages[pyPkg] = true
+ }
+ for pyPkg != "" {
+ if _, found := allPackages[pyPkg]; found {
+ break
+ }
+ allPackages[pyPkg] = true
+ pyPkg = getPackage(pyPkg)
+ }
+ }
+ }
+ noInitPackages := make([]string, 0)
+ for pyPkg := range allPackages {
+ if _, found := initedPackages[pyPkg]; !found {
+ noInitPackages = append(noInitPackages, pyPkg)
+ }
+ }
+ return noInitPackages, nil
+}
+
+// An InputZip owned by the InputZipsManager. Opened ManagedInputZip's are chained in the open order.
+type ManagedInputZip struct {
+ owner *InputZipsManager
+ realInputZip InputZip
+ older *ManagedInputZip
+ newer *ManagedInputZip
+}
+
+// Maintains the array of ManagedInputZips, keeping track of open input ones. When an InputZip is opened,
+// may close some other InputZip to limit the number of open ones.
+type InputZipsManager struct {
+ inputZips []*ManagedInputZip
+ nOpenZips int
+ maxOpenZips int
+ openInputZips *ManagedInputZip
+}
+
+func (miz *ManagedInputZip) unlink() {
+ olderMiz := miz.older
+ newerMiz := miz.newer
+ if newerMiz.older != miz || olderMiz.newer != miz {
+ panic(fmt.Errorf("removing %p:%#v: broken list between %p:%#v and %p:%#v",
+ miz, miz, newerMiz, newerMiz, olderMiz, olderMiz))
+ }
+ olderMiz.newer = newerMiz
+ newerMiz.older = olderMiz
+ miz.newer = nil
+ miz.older = nil
+}
+
+func (miz *ManagedInputZip) link(olderMiz *ManagedInputZip) {
+ if olderMiz.newer != nil || olderMiz.older != nil {
+ panic(fmt.Errorf("inputZip is already open"))
+ }
+ oldOlderMiz := miz.older
+ if oldOlderMiz.newer != miz {
+ panic(fmt.Errorf("broken list between %p:%#v and %p:%#v", miz, oldOlderMiz))
+ }
+ miz.older = olderMiz
+ olderMiz.older = oldOlderMiz
+ oldOlderMiz.newer = olderMiz
+ olderMiz.newer = miz
+}
+
+func NewInputZipsManager(nInputZips, maxOpenZips int) *InputZipsManager {
+ if maxOpenZips < 3 {
+ panic(fmt.Errorf("open zips limit should be above 3"))
+ }
+ // In the dummy element .older points to the most recently opened InputZip, and .newer points to the oldest.
+ head := new(ManagedInputZip)
+ head.older = head
+ head.newer = head
+ return &InputZipsManager{
+ inputZips: make([]*ManagedInputZip, 0, nInputZips),
+ maxOpenZips: maxOpenZips,
+ openInputZips: head,
+ }
+}
+
+// InputZip factory
+func (izm *InputZipsManager) Manage(inz InputZip) InputZip {
+ iz := &ManagedInputZip{owner: izm, realInputZip: inz}
+ izm.inputZips = append(izm.inputZips, iz)
+ return iz
+}
+
+// Opens or reopens ManagedInputZip.
+func (izm *InputZipsManager) reopen(miz *ManagedInputZip) error {
+ if miz.realInputZip.IsOpen() {
+ if miz != izm.openInputZips {
+ miz.unlink()
+ izm.openInputZips.link(miz)
+ }
+ return nil
+ }
+ if izm.nOpenZips >= izm.maxOpenZips {
+ if err := izm.close(izm.openInputZips.older); err != nil {
+ return err
+ }
+ }
+ if err := miz.realInputZip.Open(); err != nil {
+ return err
+ }
+ izm.openInputZips.link(miz)
+ izm.nOpenZips++
+ return nil
+}
+
+func (izm *InputZipsManager) close(miz *ManagedInputZip) error {
+ if miz.IsOpen() {
+ err := miz.realInputZip.Close()
+ izm.nOpenZips--
+ miz.unlink()
+ return err
+ }
+ return nil
+}
+
+// Checks that openInputZips deque is valid
+func (izm *InputZipsManager) checkOpenZipsDeque() {
+ nReallyOpen := 0
+ el := izm.openInputZips
+ for {
+ elNext := el.older
+ if elNext.newer != el {
+ panic(fmt.Errorf("Element:\n %p: %v\nNext:\n %p %v", el, el, elNext, elNext))
+ }
+ if elNext == izm.openInputZips {
+ break
+ }
+ el = elNext
+ if !el.IsOpen() {
+ panic(fmt.Errorf("Found unopened element"))
+ }
+ nReallyOpen++
+ if nReallyOpen > izm.nOpenZips {
+ panic(fmt.Errorf("found %d open zips, should be %d", nReallyOpen, izm.nOpenZips))
+ }
+ }
+ if nReallyOpen > izm.nOpenZips {
+ panic(fmt.Errorf("found %d open zips, should be %d", nReallyOpen, izm.nOpenZips))
+ }
+}
+
+func (miz *ManagedInputZip) Name() string {
+ return miz.realInputZip.Name()
+}
+
+func (miz *ManagedInputZip) Open() error {
+ return miz.owner.reopen(miz)
+}
+
+func (miz *ManagedInputZip) Close() error {
+ return miz.owner.close(miz)
+}
+
+func (miz *ManagedInputZip) IsOpen() bool {
+ return miz.realInputZip.IsOpen()
+}
+
+func (miz *ManagedInputZip) Entries() []*zip.File {
+ if !miz.IsOpen() {
+ panic(fmt.Errorf("%s: is not open", miz.Name()))
+ }
+ return miz.realInputZip.Entries()
+}
+
+// Actual processing.
+func mergeZips(inputZips []InputZip, writer *zip.Writer, manifest, pyMain string,
+ sortEntries, emulateJar, emulatePar, stripDirEntries, ignoreDuplicates bool,
+ excludeFiles, excludeDirs []string, zipsToNotStrip map[string]bool) error {
+
+ out := NewOutputZip(writer, sortEntries, emulateJar, stripDirEntries, ignoreDuplicates)
+ out.setExcludeFiles(excludeFiles)
+ out.setExcludeDirs(excludeDirs)
+ if manifest != "" {
+ if err := out.addManifest(manifest); err != nil {
+ return err
+ }
+ }
+ if pyMain != "" {
+ if err := out.addZipEntryFromFile("__main__.py", pyMain); err != nil {
+ return err
+ }
+ }
+
+ if emulatePar {
+ noInitPackages, err := out.getUninitializedPythonPackages(inputZips)
+ if err != nil {
+ return err
+ }
+ for _, uninitializedPyPackage := range noInitPackages {
+ if err = out.addEmptyEntry(filepath.Join(uninitializedPyPackage, "__init__.py")); err != nil {
+ return err
+ }
+ }
+ }
+
+ // Finally, add entries from all the input zips.
+ for _, inputZip := range inputZips {
+ _, copyFully := zipsToNotStrip[inputZip.Name()]
+ if err := inputZip.Open(); err != nil {
+ return err
+ }
+
+ for i, entry := range inputZip.Entries() {
+ if copyFully || !out.isEntryExcluded(entry.Name) {
+ if err := out.copyEntry(inputZip, i); err != nil {
+ return err
+ }
+ }
+ }
+ // Unless we need to rearrange the entries, the input zip can now be closed.
+ if !(emulateJar || sortEntries) {
+ if err := inputZip.Close(); err != nil {
+ return err
+ }
+ }
+ }
+
+ if emulateJar {
+ return out.writeEntries(out.jarSorted())
+ } else if sortEntries {
+ return out.writeEntries(out.alphanumericSorted())
+ }
+ return nil
+}
+
+// Process command line
type fileList []string
func (f *fileList) String() string {
@@ -50,9 +608,8 @@
return `""`
}
-func (s zipsToNotStripSet) Set(zip_path string) error {
- s[zip_path] = true
-
+func (s zipsToNotStripSet) Set(path string) error {
+ s[path] = true
return nil
}
@@ -60,8 +617,8 @@
sortEntries = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
emulateJar = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
emulatePar = flag.Bool("p", false, "merge zip entries based on par format")
- stripDirs fileList
- stripFiles fileList
+ excludeDirs fileList
+ excludeFiles fileList
zipsToNotStrip = make(zipsToNotStripSet)
stripDirEntries = flag.Bool("D", false, "strip directory entries from the output zip file")
manifest = flag.String("m", "", "manifest file to insert in jar")
@@ -71,14 +628,52 @@
)
func init() {
- flag.Var(&stripDirs, "stripDir", "directories to be excluded from the output zip, accepts wildcards")
- flag.Var(&stripFiles, "stripFile", "files to be excluded from the output zip, accepts wildcards")
+ flag.Var(&excludeDirs, "stripDir", "directories to be excluded from the output zip, accepts wildcards")
+ flag.Var(&excludeFiles, "stripFile", "files to be excluded from the output zip, accepts wildcards")
flag.Var(&zipsToNotStrip, "zipToNotStrip", "the input zip file which is not applicable for stripping")
}
+type FileInputZip struct {
+ name string
+ reader *zip.ReadCloser
+}
+
+func (fiz *FileInputZip) Name() string {
+ return fiz.name
+}
+
+func (fiz *FileInputZip) Close() error {
+ if fiz.IsOpen() {
+ reader := fiz.reader
+ fiz.reader = nil
+ return reader.Close()
+ }
+ return nil
+}
+
+func (fiz *FileInputZip) Entries() []*zip.File {
+ if !fiz.IsOpen() {
+ panic(fmt.Errorf("%s: is not open", fiz.Name()))
+ }
+ return fiz.reader.File
+}
+
+func (fiz *FileInputZip) IsOpen() bool {
+ return fiz.reader != nil
+}
+
+func (fiz *FileInputZip) Open() error {
+ if fiz.IsOpen() {
+ return nil
+ }
+ var err error
+ fiz.reader, err = zip.OpenReader(fiz.Name())
+ return err
+}
+
func main() {
flag.Usage = func() {
- fmt.Fprintln(os.Stderr, "usage: merge_zips [-jpsD] [-m manifest] [--prefix script] [-pm __main__.py] output [inputs...]")
+ fmt.Fprintln(os.Stderr, "usage: merge_zips [-jpsD] [-m manifest] [--prefix script] [-pm __main__.py] OutputZip [inputs...]")
flag.PrintDefaults()
}
@@ -90,16 +685,28 @@
os.Exit(1)
}
outputPath := args[0]
- inputs := args[1:]
+ inputs := make([]string, 0)
+ for _, input := range args[1:] {
+ if input[0] == '@' {
+ bytes, err := ioutil.ReadFile(input[1:])
+ if err != nil {
+ log.Fatal(err)
+ }
+ inputs = append(inputs, soongZip.ReadRespFile(bytes)...)
+ continue
+ }
+ inputs = append(inputs, input)
+ continue
+ }
log.SetFlags(log.Lshortfile)
// make writer
- output, err := os.Create(outputPath)
+ outputZip, err := os.Create(outputPath)
if err != nil {
log.Fatal(err)
}
- defer output.Close()
+ defer outputZip.Close()
var offset int64
if *prefix != "" {
@@ -107,13 +714,13 @@
if err != nil {
log.Fatal(err)
}
- offset, err = io.Copy(output, prefixFile)
+ offset, err = io.Copy(outputZip, prefixFile)
if err != nil {
log.Fatal(err)
}
}
- writer := zip.NewWriter(output)
+ writer := zip.NewWriter(outputZip)
defer func() {
err := writer.Close()
if err != nil {
@@ -122,18 +729,6 @@
}()
writer.SetOffset(offset)
- // make readers
- readers := []namedZipReader{}
- for _, input := range inputs {
- reader, err := zip.OpenReader(input)
- if err != nil {
- log.Fatal(err)
- }
- defer reader.Close()
- namedReader := namedZipReader{path: input, reader: &reader.Reader}
- readers = append(readers, namedReader)
- }
-
if *manifest != "" && !*emulateJar {
log.Fatal(errors.New("must specify -j when specifying a manifest via -m"))
}
@@ -143,344 +738,15 @@
}
// do merge
- err = mergeZips(readers, writer, *manifest, *pyMain, *sortEntries, *emulateJar, *emulatePar,
- *stripDirEntries, *ignoreDuplicates, []string(stripFiles), []string(stripDirs), map[string]bool(zipsToNotStrip))
+ inputZipsManager := NewInputZipsManager(len(inputs), 1000)
+ inputZips := make([]InputZip, len(inputs))
+ for i, input := range inputs {
+ inputZips[i] = inputZipsManager.Manage(&FileInputZip{name: input})
+ }
+ err = mergeZips(inputZips, writer, *manifest, *pyMain, *sortEntries, *emulateJar, *emulatePar,
+ *stripDirEntries, *ignoreDuplicates, []string(excludeFiles), []string(excludeDirs),
+ map[string]bool(zipsToNotStrip))
if err != nil {
log.Fatal(err)
}
}
-
-// a namedZipReader reads a .zip file and can say which file it's reading
-type namedZipReader struct {
- path string
- reader *zip.Reader
-}
-
-// a zipEntryPath refers to a file contained in a zip
-type zipEntryPath struct {
- zipName string
- entryName string
-}
-
-func (p zipEntryPath) String() string {
- return p.zipName + "/" + p.entryName
-}
-
-// a zipEntry is a zipSource that pulls its content from another zip
-type zipEntry struct {
- path zipEntryPath
- content *zip.File
-}
-
-func (ze zipEntry) String() string {
- return ze.path.String()
-}
-
-func (ze zipEntry) IsDir() bool {
- return ze.content.FileInfo().IsDir()
-}
-
-func (ze zipEntry) CRC32() uint32 {
- return ze.content.FileHeader.CRC32
-}
-
-func (ze zipEntry) Size() uint64 {
- return ze.content.FileHeader.UncompressedSize64
-}
-
-func (ze zipEntry) WriteToZip(dest string, zw *zip.Writer) error {
- return zw.CopyFrom(ze.content, dest)
-}
-
-// a bufferEntry is a zipSource that pulls its content from a []byte
-type bufferEntry struct {
- fh *zip.FileHeader
- content []byte
-}
-
-func (be bufferEntry) String() string {
- return "internal buffer"
-}
-
-func (be bufferEntry) IsDir() bool {
- return be.fh.FileInfo().IsDir()
-}
-
-func (be bufferEntry) CRC32() uint32 {
- return crc32.ChecksumIEEE(be.content)
-}
-
-func (be bufferEntry) Size() uint64 {
- return uint64(len(be.content))
-}
-
-func (be bufferEntry) WriteToZip(dest string, zw *zip.Writer) error {
- w, err := zw.CreateHeader(be.fh)
- if err != nil {
- return err
- }
-
- if !be.IsDir() {
- _, err = w.Write(be.content)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
-type zipSource interface {
- String() string
- IsDir() bool
- CRC32() uint32
- Size() uint64
- WriteToZip(dest string, zw *zip.Writer) error
-}
-
-// a fileMapping specifies to copy a zip entry from one place to another
-type fileMapping struct {
- dest string
- source zipSource
-}
-
-func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest, pyMain string,
- sortEntries, emulateJar, emulatePar, stripDirEntries, ignoreDuplicates bool,
- stripFiles, stripDirs []string, zipsToNotStrip map[string]bool) error {
-
- sourceByDest := make(map[string]zipSource, 0)
- orderedMappings := []fileMapping{}
-
- // if dest already exists returns a non-null zipSource for the existing source
- addMapping := func(dest string, source zipSource) zipSource {
- mapKey := filepath.Clean(dest)
- if existingSource, exists := sourceByDest[mapKey]; exists {
- return existingSource
- }
-
- sourceByDest[mapKey] = source
- orderedMappings = append(orderedMappings, fileMapping{source: source, dest: dest})
- return nil
- }
-
- if manifest != "" {
- if !stripDirEntries {
- dirHeader := jar.MetaDirFileHeader()
- dirSource := bufferEntry{dirHeader, nil}
- addMapping(jar.MetaDir, dirSource)
- }
-
- contents, err := ioutil.ReadFile(manifest)
- if err != nil {
- return err
- }
-
- fh, buf, err := jar.ManifestFileContents(contents)
- if err != nil {
- return err
- }
-
- fileSource := bufferEntry{fh, buf}
- addMapping(jar.ManifestFile, fileSource)
- }
-
- if pyMain != "" {
- buf, err := ioutil.ReadFile(pyMain)
- if err != nil {
- return err
- }
- fh := &zip.FileHeader{
- Name: "__main__.py",
- Method: zip.Store,
- UncompressedSize64: uint64(len(buf)),
- }
- fh.SetMode(0700)
- fh.SetModTime(jar.DefaultTime)
- fileSource := bufferEntry{fh, buf}
- addMapping("__main__.py", fileSource)
- }
-
- if emulatePar {
- // the runfiles packages needs to be populated with "__init__.py".
- newPyPkgs := []string{}
- // the runfiles dirs have been treated as packages.
- existingPyPkgSet := make(map[string]bool)
- // put existing __init__.py files to a set first. This set is used for preventing
- // generated __init__.py files from overwriting existing ones.
- for _, namedReader := range readers {
- for _, file := range namedReader.reader.File {
- if filepath.Base(file.Name) != "__init__.py" {
- continue
- }
- pyPkg := pathBeforeLastSlash(file.Name)
- if _, found := existingPyPkgSet[pyPkg]; found {
- panic(fmt.Errorf("found __init__.py path duplicates during pars merging: %q.", file.Name))
- } else {
- existingPyPkgSet[pyPkg] = true
- }
- }
- }
- for _, namedReader := range readers {
- for _, file := range namedReader.reader.File {
- var parentPath string /* the path after trimming last "/" */
- if filepath.Base(file.Name) == "__init__.py" {
- // for existing __init__.py files, we should trim last "/" for twice.
- // eg. a/b/c/__init__.py ---> a/b
- parentPath = pathBeforeLastSlash(pathBeforeLastSlash(file.Name))
- } else {
- parentPath = pathBeforeLastSlash(file.Name)
- }
- populateNewPyPkgs(parentPath, existingPyPkgSet, &newPyPkgs)
- }
- }
- for _, pkg := range newPyPkgs {
- var emptyBuf []byte
- fh := &zip.FileHeader{
- Name: filepath.Join(pkg, "__init__.py"),
- Method: zip.Store,
- UncompressedSize64: uint64(len(emptyBuf)),
- }
- fh.SetMode(0700)
- fh.SetModTime(jar.DefaultTime)
- fileSource := bufferEntry{fh, emptyBuf}
- addMapping(filepath.Join(pkg, "__init__.py"), fileSource)
- }
- }
- for _, namedReader := range readers {
- _, skipStripThisZip := zipsToNotStrip[namedReader.path]
- for _, file := range namedReader.reader.File {
- if !skipStripThisZip {
- if skip, err := shouldStripEntry(emulateJar, stripFiles, stripDirs, file.Name); err != nil {
- return err
- } else if skip {
- continue
- }
- }
-
- if stripDirEntries && file.FileInfo().IsDir() {
- continue
- }
-
- // check for other files or directories destined for the same path
- dest := file.Name
-
- // make a new entry to add
- source := zipEntry{path: zipEntryPath{zipName: namedReader.path, entryName: file.Name}, content: file}
-
- if existingSource := addMapping(dest, source); existingSource != nil {
- // handle duplicates
- if existingSource.IsDir() != source.IsDir() {
- return fmt.Errorf("Directory/file mismatch at %v from %v and %v\n",
- dest, existingSource, source)
- }
-
- if ignoreDuplicates {
- continue
- }
-
- if emulateJar &&
- file.Name == jar.ManifestFile || file.Name == jar.ModuleInfoClass {
- // Skip manifest and module info files that are not from the first input file
- continue
- }
-
- if source.IsDir() {
- continue
- }
-
- if existingSource.CRC32() == source.CRC32() && existingSource.Size() == source.Size() {
- continue
- }
-
- return fmt.Errorf("Duplicate path %v found in %v and %v\n",
- dest, existingSource, source)
- }
- }
- }
-
- if emulateJar {
- jarSort(orderedMappings)
- } else if sortEntries {
- alphanumericSort(orderedMappings)
- }
-
- for _, entry := range orderedMappings {
- if err := entry.source.WriteToZip(entry.dest, writer); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-// Sets the given directory and all its ancestor directories as Python packages.
-func populateNewPyPkgs(pkgPath string, existingPyPkgSet map[string]bool, newPyPkgs *[]string) {
- for pkgPath != "" {
- if _, found := existingPyPkgSet[pkgPath]; !found {
- existingPyPkgSet[pkgPath] = true
- *newPyPkgs = append(*newPyPkgs, pkgPath)
- // Gets its ancestor directory by trimming last slash.
- pkgPath = pathBeforeLastSlash(pkgPath)
- } else {
- break
- }
- }
-}
-
-func pathBeforeLastSlash(path string) string {
- ret := filepath.Dir(path)
- // filepath.Dir("abc") -> "." and filepath.Dir("/abc") -> "/".
- if ret == "." || ret == "/" {
- return ""
- }
- return ret
-}
-
-func shouldStripEntry(emulateJar bool, stripFiles, stripDirs []string, name string) (bool, error) {
- for _, dir := range stripDirs {
- dir = filepath.Clean(dir)
- patterns := []string{
- dir + "/", // the directory itself
- dir + "/**/*", // files recursively in the directory
- dir + "/**/*/", // directories recursively in the directory
- }
-
- for _, pattern := range patterns {
- match, err := pathtools.Match(pattern, name)
- if err != nil {
- return false, fmt.Errorf("%s: %s", err.Error(), pattern)
- } else if match {
- if emulateJar {
- // When merging jar files, don't strip META-INF/MANIFEST.MF even if stripping META-INF is
- // requested.
- // TODO(ccross): which files does this affect?
- if name != jar.MetaDir && name != jar.ManifestFile {
- return true, nil
- }
- }
- return true, nil
- }
- }
- }
-
- for _, pattern := range stripFiles {
- if match, err := pathtools.Match(pattern, name); err != nil {
- return false, fmt.Errorf("%s: %s", err.Error(), pattern)
- } else if match {
- return true, nil
- }
- }
- return false, nil
-}
-
-func jarSort(files []fileMapping) {
- sort.SliceStable(files, func(i, j int) bool {
- return jar.EntryNamesLess(files[i].dest, files[j].dest)
- })
-}
-
-func alphanumericSort(files []fileMapping) {
- sort.SliceStable(files, func(i, j int) bool {
- return files[i].dest < files[j].dest
- })
-}
diff --git a/cmd/merge_zips/merge_zips_test.go b/cmd/merge_zips/merge_zips_test.go
index dbde270..cb58436 100644
--- a/cmd/merge_zips/merge_zips_test.go
+++ b/cmd/merge_zips/merge_zips_test.go
@@ -51,6 +51,39 @@
moduleInfoFile = testZipEntry{jar.ModuleInfoClass, 0755, []byte("module-info")}
)
+type testInputZip struct {
+ name string
+ entries []testZipEntry
+ reader *zip.Reader
+}
+
+func (tiz *testInputZip) Name() string {
+ return tiz.name
+}
+
+func (tiz *testInputZip) Open() error {
+ if tiz.reader == nil {
+ tiz.reader = testZipEntriesToZipReader(tiz.entries)
+ }
+ return nil
+}
+
+func (tiz *testInputZip) Close() error {
+ tiz.reader = nil
+ return nil
+}
+
+func (tiz *testInputZip) Entries() []*zip.File {
+ if tiz.reader == nil {
+ panic(fmt.Errorf("%s: should be open to get entries", tiz.Name()))
+ }
+ return tiz.reader.File
+}
+
+func (tiz *testInputZip) IsOpen() bool {
+ return tiz.reader != nil
+}
+
func TestMergeZips(t *testing.T) {
testCases := []struct {
name string
@@ -207,13 +240,9 @@
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
- var readers []namedZipReader
+ inputZips := make([]InputZip, len(test.in))
for i, in := range test.in {
- r := testZipEntriesToZipReader(in)
- readers = append(readers, namedZipReader{
- path: "in" + strconv.Itoa(i),
- reader: r,
- })
+ inputZips[i] = &testInputZip{name: "in" + strconv.Itoa(i), entries: in}
}
want := testZipEntriesToBuf(test.out)
@@ -221,7 +250,7 @@
out := &bytes.Buffer{}
writer := zip.NewWriter(out)
- err := mergeZips(readers, writer, "", "",
+ err := mergeZips(inputZips, writer, "", "",
test.sort, test.jar, false, test.stripDirEntries, test.ignoreDuplicates,
test.stripFiles, test.stripDirs, test.zipsToNotStrip)
@@ -304,3 +333,60 @@
return ret
}
+
+type DummyInpuZip struct {
+ isOpen bool
+}
+
+func (diz *DummyInpuZip) Name() string {
+ return "dummy"
+}
+
+func (diz *DummyInpuZip) Open() error {
+ diz.isOpen = true
+ return nil
+}
+
+func (diz *DummyInpuZip) Close() error {
+ diz.isOpen = false
+ return nil
+}
+
+func (DummyInpuZip) Entries() []*zip.File {
+ panic("implement me")
+}
+
+func (diz *DummyInpuZip) IsOpen() bool {
+ return diz.isOpen
+}
+
+func TestInputZipsManager(t *testing.T) {
+ const nInputZips = 20
+ const nMaxOpenZips = 10
+ izm := NewInputZipsManager(20, 10)
+ managedZips := make([]InputZip, nInputZips)
+ for i := 0; i < nInputZips; i++ {
+ managedZips[i] = izm.Manage(&DummyInpuZip{})
+ }
+
+ t.Run("InputZipsManager", func(t *testing.T) {
+ for i, iz := range managedZips {
+ if err := iz.Open(); err != nil {
+ t.Fatalf("Step %d: open failed: %s", i, err)
+ return
+ }
+ if izm.nOpenZips > nMaxOpenZips {
+ t.Errorf("Step %d: should be <=%d open zips", i, nMaxOpenZips)
+ }
+ }
+ if !managedZips[nInputZips-1].IsOpen() {
+ t.Error("The last input should stay open")
+ }
+ for _, iz := range managedZips {
+ iz.Close()
+ }
+ if izm.nOpenZips > 0 {
+ t.Error("Some input zips are still open")
+ }
+ })
+}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 0bc3606..39303bf 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -331,42 +331,36 @@
}
buildActionFlags := []struct {
- name string
- description string
- action build.BuildAction
- buildDependencies bool
- set bool
+ name string
+ description string
+ action build.BuildAction
+ set bool
}{{
- name: "all-modules",
- description: "Build action: build from the top of the source tree.",
- action: build.BUILD_MODULES,
- buildDependencies: true,
+ name: "all-modules",
+ description: "Build action: build from the top of the source tree.",
+ action: build.BUILD_MODULES,
}, {
- // buildDependencies is set to true as mm is being deprecated. This is redirecting to mma build
- // command behaviour. Once it has soaked for a while, the build command is deleted from here once
- // it has been removed from the envsetup.sh.
- name: "modules-in-a-dir-no-deps",
- description: "Build action: builds all of the modules in the current directory without their dependencies.",
- action: build.BUILD_MODULES_IN_A_DIRECTORY,
- buildDependencies: true,
+ // This is redirecting to mma build command behaviour. Once it has soaked for a
+ // while, the build command is deleted from here once it has been removed from the
+ // envsetup.sh.
+ name: "modules-in-a-dir-no-deps",
+ description: "Build action: builds all of the modules in the current directory without their dependencies.",
+ action: build.BUILD_MODULES_IN_A_DIRECTORY,
}, {
- // buildDependencies is set to true as mmm is being deprecated. This is redirecting to mmma build
- // command behaviour. Once it has soaked for a while, the build command is deleted from here once
- // it has been removed from the envsetup.sh.
- name: "modules-in-dirs-no-deps",
- description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
- action: build.BUILD_MODULES_IN_DIRECTORIES,
- buildDependencies: true,
+ // This is redirecting to mmma build command behaviour. Once it has soaked for a
+ // while, the build command is deleted from here once it has been removed from the
+ // envsetup.sh.
+ name: "modules-in-dirs-no-deps",
+ description: "Build action: builds all of the modules in the supplied directories without their dependencies.",
+ action: build.BUILD_MODULES_IN_DIRECTORIES,
}, {
- name: "modules-in-a-dir",
- description: "Build action: builds all of the modules in the current directory and their dependencies.",
- action: build.BUILD_MODULES_IN_A_DIRECTORY,
- buildDependencies: true,
+ name: "modules-in-a-dir",
+ description: "Build action: builds all of the modules in the current directory and their dependencies.",
+ action: build.BUILD_MODULES_IN_A_DIRECTORY,
}, {
- name: "modules-in-dirs",
- description: "Build action: builds all of the modules in the supplied directories and their dependencies.",
- action: build.BUILD_MODULES_IN_DIRECTORIES,
- buildDependencies: true,
+ name: "modules-in-dirs",
+ description: "Build action: builds all of the modules in the supplied directories and their dependencies.",
+ action: build.BUILD_MODULES_IN_DIRECTORIES,
}}
for i, flag := range buildActionFlags {
flags.BoolVar(&buildActionFlags[i].set, flag.name, false, flag.description)
@@ -386,12 +380,10 @@
// is specified.
buildActionCount := 0
var buildAction build.BuildAction
- buildDependency := false
for _, flag := range buildActionFlags {
if flag.set {
buildActionCount++
buildAction = flag.action
- buildDependency = flag.buildDependencies
}
}
if buildActionCount != 1 {
@@ -403,7 +395,7 @@
// Remove the build action flags from the args as they are not recognized by the config.
args = args[numBuildActionFlags:]
- return build.NewBuildActionConfig(buildAction, *dir, buildDependency, ctx, args...)
+ return build.NewBuildActionConfig(buildAction, *dir, ctx, args...)
}
func make(ctx build.Context, config build.Config, _ []string, logsDir string) {
@@ -425,17 +417,13 @@
if _, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
writer := ctx.Writer
- fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is deprecated, and will be removed shortly.")
+ fmt.Fprintln(writer, "! The variable `ONE_SHOT_MAKEFILE` is obsolete.")
fmt.Fprintln(writer, "!")
fmt.Fprintln(writer, "! If you're using `mm`, you'll need to run `source build/envsetup.sh` to update.")
fmt.Fprintln(writer, "!")
fmt.Fprintln(writer, "! Otherwise, either specify a module name with m, or use mma / MODULES-IN-...")
fmt.Fprintln(writer, "")
- select {
- case <-time.After(30 * time.Second):
- case <-ctx.Done():
- return
- }
+ ctx.Fatal("done")
}
toBuild := build.BuildAll
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
new file mode 100644
index 0000000..792edf3
--- /dev/null
+++ b/java/platform_compat_config.go
@@ -0,0 +1,92 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterModuleType("platform_compat_config", platformCompatConfigFactory)
+}
+
+type platformCompatConfigProperties struct {
+ Src *string `android:"path"`
+ Prefix *string
+}
+
+type platformCompatConfig struct {
+ android.ModuleBase
+
+ properties platformCompatConfigProperties
+ installDirPath android.OutputPath
+ configFile android.OutputPath
+}
+
+func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ rule := android.NewRuleBuilder()
+
+ configFileName := String(p.properties.Prefix) + "_platform_compat_config.xml"
+ p.configFile = android.PathForModuleOut(ctx, configFileName).OutputPath
+ path := android.PathForModuleSrc(ctx, String(p.properties.Src))
+
+ // Use the empty config if the compat config file idoesn't exist (can happen if @ChangeId
+ // annotation is not used).
+ emptyConfig := `<?xml version="1.0" encoding="UTF-8" standalone="no"?><config/>`
+ configPath := `compat/compat_config.xml`
+
+ rule.Command().
+ Text(`unzip`).
+ Flag(`-l`).
+ Input(path).
+ Text(`| grep`).
+ Flag(`-q`).
+ Text(configPath).
+ Text(`; if [ "$?" = "0" ] ; then`).
+ Text(`unzip`).
+ Flag(`-qp`).
+ Input(path).
+ Text(configPath).
+ Text(`>`).
+ Output(p.configFile).
+ Text(`; else echo '`).
+ Text(emptyConfig).
+ Text(`' >`).
+ Output(p.configFile).
+ Text(`; fi`)
+
+ p.installDirPath = android.PathForModuleInstall(ctx, "etc", "sysconfig")
+ rule.Build(pctx, ctx, configFileName, "Extract compat/compat_config.xml and install it")
+
+}
+
+func (p *platformCompatConfig) AndroidMkEntries() android.AndroidMkEntries {
+ return android.AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(p.configFile),
+ Include: "$(BUILD_PREBUILT)",
+ AddCustomEntries: func(name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.configFile.Base())
+ },
+ }
+}
+
+func platformCompatConfigFactory() android.Module {
+ module := &platformCompatConfig{}
+ module.AddProperties(&module.properties)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 31f5922..8c59cbc 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -69,3 +69,19 @@
},
test_suites: ["general-tests"],
}
+
+python_binary_host {
+ name: "jsonmodify",
+ main: "jsonmodify.py",
+ srcs: [
+ "jsonmodify.py",
+ ],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ }
+}
diff --git a/scripts/jsonmodify.py b/scripts/jsonmodify.py
new file mode 100755
index 0000000..4b2c3c2
--- /dev/null
+++ b/scripts/jsonmodify.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import argparse
+import collections
+import json
+import sys
+
+def follow_path(obj, path):
+ cur = obj
+ last_key = None
+ for key in path.split('.'):
+ if last_key:
+ if last_key not in cur:
+ return None,None
+ cur = cur[last_key]
+ last_key = key
+ if last_key not in cur:
+ return None,None
+ return cur, last_key
+
+
+def ensure_path(obj, path):
+ cur = obj
+ last_key = None
+ for key in path.split('.'):
+ if last_key:
+ if last_key not in cur:
+ cur[last_key] = dict()
+ cur = cur[last_key]
+ last_key = key
+ return cur, last_key
+
+
+class SetValue(str):
+ def apply(self, obj, val):
+ cur, key = ensure_path(obj, self)
+ cur[key] = val
+
+
+class Replace(str):
+ def apply(self, obj, val):
+ cur, key = follow_path(obj, self)
+ if cur:
+ cur[key] = val
+
+
+class Remove(str):
+ def apply(self, obj):
+ cur, key = follow_path(obj, self)
+ if cur:
+ del cur[key]
+
+
+class AppendList(str):
+ def apply(self, obj, *args):
+ cur, key = ensure_path(obj, self)
+ if key not in cur:
+ cur[key] = list()
+ if not isinstance(cur[key], list):
+ raise ValueError(self + " should be a array.")
+ cur[key].extend(args)
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-o', '--out',
+ help='write result to a file. If omitted, print to stdout',
+ metavar='output',
+ action='store')
+ parser.add_argument('input', nargs='?', help='JSON file')
+ parser.add_argument("-v", "--value", type=SetValue,
+ help='set value of the key specified by path. If path doesn\'t exist, creates new one.',
+ metavar=('path', 'value'),
+ nargs=2, dest='patch', default=[], action='append')
+ parser.add_argument("-s", "--replace", type=Replace,
+ help='replace value of the key specified by path. If path doesn\'t exist, no op.',
+ metavar=('path', 'value'),
+ nargs=2, dest='patch', action='append')
+ parser.add_argument("-r", "--remove", type=Remove,
+ help='remove the key specified by path. If path doesn\'t exist, no op.',
+ metavar='path',
+ nargs=1, dest='patch', action='append')
+ parser.add_argument("-a", "--append_list", type=AppendList,
+ help='append values to the list specified by path. If path doesn\'t exist, creates new list for it.',
+ metavar=('path', 'value'),
+ nargs='+', dest='patch', default=[], action='append')
+ args = parser.parse_args()
+
+ if args.input:
+ with open(args.input) as f:
+ obj = json.load(f, object_pairs_hook=collections.OrderedDict)
+ else:
+ obj = json.load(sys.stdin, object_pairs_hook=collections.OrderedDict)
+
+ for p in args.patch:
+ p[0].apply(obj, *p[1:])
+
+ if args.out:
+ with open(args.out, "w") as f:
+ json.dump(obj, f, indent=2)
+ else:
+ print(json.dumps(obj, indent=2))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/ui/build/config.go b/ui/build/config.go
index bcb1965..434047b 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -253,13 +253,13 @@
// NewBuildActionConfig returns a build configuration based on the build action. The arguments are
// processed based on the build action and extracts any arguments that belongs to the build action.
-func NewBuildActionConfig(action BuildAction, dir string, buildDependencies bool, ctx Context, args ...string) Config {
- return NewConfig(ctx, getConfigArgs(action, dir, buildDependencies, ctx, args)...)
+func NewBuildActionConfig(action BuildAction, dir string, ctx Context, args ...string) Config {
+ return NewConfig(ctx, getConfigArgs(action, dir, ctx, args)...)
}
// getConfigArgs processes the command arguments based on the build action and creates a set of new
// arguments to be accepted by Config.
-func getConfigArgs(action BuildAction, dir string, buildDependencies bool, ctx Context, args []string) []string {
+func getConfigArgs(action BuildAction, dir string, ctx Context, args []string) []string {
// The next block of code verifies that the current directory is the root directory of the source
// tree. It then finds the relative path of dir based on the root directory of the source tree
// and verify that dir is inside of the source tree.
@@ -295,7 +295,6 @@
configArgs = removeFromList("GET-INSTALL-PATH", configArgs)
}
- var buildFiles []string
var targets []string
switch action {
@@ -312,20 +311,11 @@
if buildFile == "" {
ctx.Fatalf("Build file not found for %s directory", relDir)
}
- buildFiles = []string{buildFile}
targets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
case BUILD_MODULES_IN_DIRECTORIES:
newConfigArgs, dirs := splitArgs(configArgs)
configArgs = newConfigArgs
- targets, buildFiles = getTargetsFromDirs(ctx, relDir, dirs, targetNamePrefix)
- }
-
- // This is to support building modules without building their dependencies. Soon, this will be
- // deprecated.
- if !buildDependencies && len(buildFiles) > 0 {
- if err := os.Setenv("ONE_SHOT_MAKEFILE", strings.Join(buildFiles, " ")); err != nil {
- ctx.Fatalf("Unable to set ONE_SHOT_MAKEFILE environment variable: %v", err)
- }
+ targets = getTargetsFromDirs(ctx, relDir, dirs, targetNamePrefix)
}
// Tidy only override all other specified targets.
@@ -435,7 +425,7 @@
// directory from the dirs list does not exist, a fatal error is raised. relDir is related to the
// source root tree where the build action command was invoked. Each directory is validated if the
// build file can be found and follows the format "dir1:target1,target2,...". Target is optional.
-func getTargetsFromDirs(ctx Context, relDir string, dirs []string, targetNamePrefix string) (targets []string, buildFiles []string) {
+func getTargetsFromDirs(ctx Context, relDir string, dirs []string, targetNamePrefix string) (targets []string) {
for _, dir := range dirs {
// The directory may have specified specific modules to build. ":" is the separator to separate
// the directory and the list of modules.
@@ -466,20 +456,18 @@
if !hasBuildFile(ctx, dir) {
ctx.Fatalf("Couldn't locate a build file from %s directory", dir)
}
- buildFiles = append(buildFiles, filepath.Join(dir, "Android.mk"))
} else {
buildFile := findBuildFile(ctx, dir)
if buildFile == "" {
ctx.Fatalf("Build file not found for %s directory", dir)
}
newTargets = []string{convertToTarget(filepath.Dir(buildFile), targetNamePrefix)}
- buildFiles = append(buildFiles, buildFile)
}
targets = append(targets, newTargets...)
}
- return targets, buildFiles
+ return targets
}
func (c *configImpl) parseArgs(ctx Context, args []string) {
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index 463405a..df618c4 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -363,19 +363,15 @@
// Expected targets from the function.
expectedTargets []string
- // Expected build from the build system.
- expectedBuildFiles []string
-
// Expecting error from running test case.
errStr string
}{{
- description: "one target dir specified",
- dirsInTrees: []string{"0/1/2/3"},
- buildFiles: []string{"0/1/2/3/Android.bp"},
- dirs: []string{"1/2/3"},
- curDir: "0",
- expectedTargets: []string{"MODULES-IN-0-1-2-3"},
- expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+ description: "one target dir specified",
+ dirsInTrees: []string{"0/1/2/3"},
+ buildFiles: []string{"0/1/2/3/Android.bp"},
+ dirs: []string{"1/2/3"},
+ curDir: "0",
+ expectedTargets: []string{"MODULES-IN-0-1-2-3"},
}, {
description: "one target dir specified, build file does not exist",
dirsInTrees: []string{"0/1/2/3"},
@@ -391,21 +387,19 @@
curDir: "0",
errStr: "1/2/3:t1:t2 not in proper directory:target1,target2,... format (\":\" was specified more than once)",
}, {
- description: "one target dir specified, no targets specified but has colon",
- dirsInTrees: []string{"0/1/2/3"},
- buildFiles: []string{"0/1/2/3/Android.bp"},
- dirs: []string{"1/2/3:"},
- curDir: "0",
- expectedTargets: []string{"MODULES-IN-0-1-2-3"},
- expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+ description: "one target dir specified, no targets specified but has colon",
+ dirsInTrees: []string{"0/1/2/3"},
+ buildFiles: []string{"0/1/2/3/Android.bp"},
+ dirs: []string{"1/2/3:"},
+ curDir: "0",
+ expectedTargets: []string{"MODULES-IN-0-1-2-3"},
}, {
- description: "one target dir specified, two targets specified",
- dirsInTrees: []string{"0/1/2/3"},
- buildFiles: []string{"0/1/2/3/Android.bp"},
- dirs: []string{"1/2/3:t1,t2"},
- curDir: "0",
- expectedTargets: []string{"t1", "t2"},
- expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+ description: "one target dir specified, two targets specified",
+ dirsInTrees: []string{"0/1/2/3"},
+ buildFiles: []string{"0/1/2/3/Android.bp"},
+ dirs: []string{"1/2/3:t1,t2"},
+ curDir: "0",
+ expectedTargets: []string{"t1", "t2"},
}, {
description: "one target dir specified, no targets and has a comma",
dirsInTrees: []string{"0/1/2/3"},
@@ -428,13 +422,12 @@
curDir: "0",
errStr: "0/1/2/3 not in proper directory:target1,target2,... format",
}, {
- description: "one target dir specified, many targets specified",
- dirsInTrees: []string{"0/1/2/3"},
- buildFiles: []string{"0/1/2/3/Android.bp"},
- dirs: []string{"1/2/3:t1,t2,t3,t4,t5,t6,t7,t8,t9,t10"},
- curDir: "0",
- expectedTargets: []string{"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10"},
- expectedBuildFiles: []string{"0/1/2/3/Android.mk"},
+ description: "one target dir specified, many targets specified",
+ dirsInTrees: []string{"0/1/2/3"},
+ buildFiles: []string{"0/1/2/3/Android.bp"},
+ dirs: []string{"1/2/3:t1,t2,t3,t4,t5,t6,t7,t8,t9,t10"},
+ curDir: "0",
+ expectedTargets: []string{"t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "t9", "t10"},
}, {
description: "one target dir specified, one target specified, build file does not exist",
dirsInTrees: []string{"0/1/2/3"},
@@ -450,29 +443,26 @@
curDir: "0",
errStr: "Couldn't locate a build file from 0/1/2/3 directory",
}, {
- description: "one target dir specified, build file not in target dir",
- dirsInTrees: []string{"0/1/2/3"},
- buildFiles: []string{"0/1/2/Android.mk"},
- dirs: []string{"1/2/3"},
- curDir: "0",
- expectedTargets: []string{"MODULES-IN-0-1-2"},
- expectedBuildFiles: []string{"0/1/2/Android.mk"},
+ description: "one target dir specified, build file not in target dir",
+ dirsInTrees: []string{"0/1/2/3"},
+ buildFiles: []string{"0/1/2/Android.mk"},
+ dirs: []string{"1/2/3"},
+ curDir: "0",
+ expectedTargets: []string{"MODULES-IN-0-1-2"},
}, {
- description: "multiple targets dir specified, targets specified",
- dirsInTrees: []string{"0/1/2/3", "0/3/4"},
- buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
- dirs: []string{"1/2/3:t1,t2", "3/4:t3,t4,t5"},
- curDir: "0",
- expectedTargets: []string{"t1", "t2", "t3", "t4", "t5"},
- expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
+ description: "multiple targets dir specified, targets specified",
+ dirsInTrees: []string{"0/1/2/3", "0/3/4"},
+ buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
+ dirs: []string{"1/2/3:t1,t2", "3/4:t3,t4,t5"},
+ curDir: "0",
+ expectedTargets: []string{"t1", "t2", "t3", "t4", "t5"},
}, {
- description: "multiple targets dir specified, one directory has targets specified",
- dirsInTrees: []string{"0/1/2/3", "0/3/4"},
- buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
- dirs: []string{"1/2/3:t1,t2", "3/4"},
- curDir: "0",
- expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
- expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
+ description: "multiple targets dir specified, one directory has targets specified",
+ dirsInTrees: []string{"0/1/2/3", "0/3/4"},
+ buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
+ dirs: []string{"1/2/3:t1,t2", "3/4"},
+ curDir: "0",
+ expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
}, {
description: "two dirs specified, only one dir exist",
dirsInTrees: []string{"0/1/2/3"},
@@ -481,13 +471,12 @@
curDir: "0",
errStr: "couldn't find directory 0/3/4",
}, {
- description: "multiple targets dirs specified at root source tree",
- dirsInTrees: []string{"0/1/2/3", "0/3/4"},
- buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
- dirs: []string{"0/1/2/3:t1,t2", "0/3/4"},
- curDir: ".",
- expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
- expectedBuildFiles: []string{"0/1/2/3/Android.mk", "0/3/4/Android.mk"},
+ description: "multiple targets dirs specified at root source tree",
+ dirsInTrees: []string{"0/1/2/3", "0/3/4"},
+ buildFiles: []string{"0/1/2/3/Android.bp", "0/3/4/Android.mk"},
+ dirs: []string{"0/1/2/3:t1,t2", "0/3/4"},
+ curDir: ".",
+ expectedTargets: []string{"t1", "t2", "MODULES-IN-0-3-4"},
}, {
description: "no directories specified",
dirsInTrees: []string{"0/1/2/3", "0/3/4"},
@@ -518,13 +507,10 @@
r := setTop(t, topDir)
defer r()
- targets, buildFiles := getTargetsFromDirs(ctx, tt.curDir, tt.dirs, "MODULES-IN-")
+ targets := getTargetsFromDirs(ctx, tt.curDir, tt.dirs, "MODULES-IN-")
if !reflect.DeepEqual(targets, tt.expectedTargets) {
t.Errorf("expected %v, got %v for targets", tt.expectedTargets, targets)
}
- if !reflect.DeepEqual(buildFiles, tt.expectedBuildFiles) {
- t.Errorf("expected %v, got %v for build files", tt.expectedBuildFiles, buildFiles)
- }
// If the execution reached here and there was an expected error code, the unit test case failed.
if tt.errStr != "" {
@@ -732,14 +718,11 @@
// Expected arguments to be in Config instance.
expectedArgs []string
- // Expected environment variables to be set.
- expectedEnvVars []envVar
-
// Expecting error from running test case.
expectedErrStr string
}
-func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction, buildDependencies bool) {
+func testGetConfigArgs(t *testing.T, tt buildActionTestCase, action BuildAction) {
ctx := testContext()
defer logger.Recover(func(err error) {
@@ -753,7 +736,6 @@
// Environment variables to set it to blank on every test case run.
resetEnvVars := []string{
- "ONE_SHOT_MAKEFILE",
"WITH_TIDY_ONLY",
}
@@ -807,17 +789,11 @@
t.Fatalf("failed to create %s file: %v", srcDirFileCheck, err)
}
- args := getConfigArgs(action, tt.curDir, buildDependencies, ctx, tt.args)
+ args := getConfigArgs(action, tt.curDir, ctx, tt.args)
if !reflect.DeepEqual(tt.expectedArgs, args) {
t.Fatalf("expected %v, got %v for config arguments", tt.expectedArgs, args)
}
- for _, env := range tt.expectedEnvVars {
- if val := os.Getenv(env.name); val != env.value {
- t.Errorf("expecting %s, got %s for environment variable %s", env.value, val, env.name)
- }
- }
-
// If the execution reached here and there was an expected error code, the unit test case failed.
if tt.expectedErrStr != "" {
t.Errorf("expecting error %s", tt.expectedErrStr)
@@ -826,299 +802,143 @@
func TestGetConfigArgsBuildModules(t *testing.T) {
tests := []buildActionTestCase{{
- description: "normal execution from the root source tree directory",
- dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
- buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "0/3/Android.mk"},
- args: []string{"-j", "fake_module", "fake_module2"},
- curDir: ".",
- tidyOnly: "",
- expectedArgs: []string{"-j", "fake_module", "fake_module2"},
- expectedEnvVars: []envVar{},
+ description: "normal execution from the root source tree directory",
+ dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
+ buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "0/3/Android.mk"},
+ args: []string{"-j", "fake_module", "fake_module2"},
+ curDir: ".",
+ tidyOnly: "",
+ expectedArgs: []string{"-j", "fake_module", "fake_module2"},
}, {
- description: "normal execution in deep directory",
- dirsInTrees: []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
- buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
- args: []string{"-j", "fake_module", "fake_module2", "-k"},
- curDir: "1/2/3/4/5/6/7/8/9",
- tidyOnly: "",
- expectedArgs: []string{"-j", "fake_module", "fake_module2", "-k"},
- expectedEnvVars: []envVar{},
+ description: "normal execution in deep directory",
+ dirsInTrees: []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
+ buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
+ args: []string{"-j", "fake_module", "fake_module2", "-k"},
+ curDir: "1/2/3/4/5/6/7/8/9",
+ tidyOnly: "",
+ expectedArgs: []string{"-j", "fake_module", "fake_module2", "-k"},
}, {
- description: "normal execution in deep directory, no targets",
- dirsInTrees: []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
- buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
- args: []string{"-j", "-k"},
- curDir: "1/2/3/4/5/6/7/8/9",
- tidyOnly: "",
- expectedArgs: []string{"-j", "-k"},
- expectedEnvVars: []envVar{},
+ description: "normal execution in deep directory, no targets",
+ dirsInTrees: []string{"0/1/2", "0/2", "0/3", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6"},
+ buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp", "1/2/3/4/5/6/7/8/9/1/2/3/4/5/6/Android.mk"},
+ args: []string{"-j", "-k"},
+ curDir: "1/2/3/4/5/6/7/8/9",
+ tidyOnly: "",
+ expectedArgs: []string{"-j", "-k"},
}, {
- description: "normal execution in root source tree, no args",
- dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
- buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp"},
- args: []string{},
- curDir: "0/2",
- tidyOnly: "",
- expectedArgs: []string{},
- expectedEnvVars: []envVar{},
+ description: "normal execution in root source tree, no args",
+ dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
+ buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp"},
+ args: []string{},
+ curDir: "0/2",
+ tidyOnly: "",
+ expectedArgs: []string{},
}, {
- description: "normal execution in symlink root source tree, no args",
- dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
- buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp"},
- rootSymlink: true,
- args: []string{},
- curDir: "0/2",
- tidyOnly: "",
- expectedArgs: []string{},
- expectedEnvVars: []envVar{},
+ description: "normal execution in symlink root source tree, no args",
+ dirsInTrees: []string{"0/1/2", "0/2", "0/3"},
+ buildFiles: []string{"0/1/2/Android.mk", "0/2/Android.bp"},
+ rootSymlink: true,
+ args: []string{},
+ curDir: "0/2",
+ tidyOnly: "",
+ expectedArgs: []string{},
}}
for _, tt := range tests {
t.Run("build action BUILD_MODULES with dependencies, "+tt.description, func(t *testing.T) {
- testGetConfigArgs(t, tt, BUILD_MODULES, true)
- })
- }
-}
-
-// TODO: Remove this test case once mm shell build command has been deprecated.
-func TestGetConfigArgsBuildModulesInDirecotoryNoDeps(t *testing.T) {
- tests := []buildActionTestCase{{
- description: "normal execution in a directory",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/2/Android.mk"},
- args: []string{"-j", "-k", "showcommands", "fake-module"},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"-j", "-k", "showcommands", "fake-module", "MODULES-IN-0-1-2"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: "0/1/2/Android.mk"}},
- }, {
- description: "makefile in parent directory",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/Android.mk"},
- args: []string{},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"MODULES-IN-0-1"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: "0/1/Android.mk"}},
- }, {
- description: "build file not found",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{},
- args: []string{},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"MODULES-IN-0-1-2"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: "0/1/2/Android.mk"}},
- expectedErrStr: "Build file not found for 0/1/2 directory",
- }, {
- description: "build action executed at root directory",
- dirsInTrees: []string{},
- buildFiles: []string{},
- args: []string{},
- curDir: ".",
- tidyOnly: "",
- expectedArgs: []string{},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: ""}},
- }, {
- description: "GET-INSTALL-PATH specified,",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/Android.mk"},
- args: []string{"GET-INSTALL-PATH"},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: "0/1/Android.mk"}},
- }, {
- description: "tidy only environment variable specified,",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/Android.mk"},
- args: []string{"GET-INSTALL-PATH"},
- curDir: "0/1/2",
- tidyOnly: "true",
- expectedArgs: []string{"tidy_only"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: "0/1/Android.mk"}},
- }}
- for _, tt := range tests {
- t.Run("build action BUILD_MODULES_IN_DIR without their dependencies, "+tt.description, func(t *testing.T) {
- testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY, false)
+ testGetConfigArgs(t, tt, BUILD_MODULES)
})
}
}
func TestGetConfigArgsBuildModulesInDirectory(t *testing.T) {
tests := []buildActionTestCase{{
- description: "normal execution in a directory",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/2/Android.mk"},
- args: []string{"fake-module"},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
- expectedEnvVars: []envVar{},
+ description: "normal execution in a directory",
+ dirsInTrees: []string{"0/1/2"},
+ buildFiles: []string{"0/1/2/Android.mk"},
+ args: []string{"fake-module"},
+ curDir: "0/1/2",
+ tidyOnly: "",
+ expectedArgs: []string{"fake-module", "MODULES-IN-0-1-2"},
}, {
- description: "build file in parent directory",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/Android.mk"},
- args: []string{},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"MODULES-IN-0-1"},
- expectedEnvVars: []envVar{},
+ description: "build file in parent directory",
+ dirsInTrees: []string{"0/1/2"},
+ buildFiles: []string{"0/1/Android.mk"},
+ args: []string{},
+ curDir: "0/1/2",
+ tidyOnly: "",
+ expectedArgs: []string{"MODULES-IN-0-1"},
},
{
- description: "build file in parent directory, multiple module names passed in",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/Android.mk"},
- args: []string{"fake-module1", "fake-module2", "fake-module3"},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"fake-module1", "fake-module2", "fake-module3", "MODULES-IN-0-1"},
- expectedEnvVars: []envVar{},
+ description: "build file in parent directory, multiple module names passed in",
+ dirsInTrees: []string{"0/1/2"},
+ buildFiles: []string{"0/1/Android.mk"},
+ args: []string{"fake-module1", "fake-module2", "fake-module3"},
+ curDir: "0/1/2",
+ tidyOnly: "",
+ expectedArgs: []string{"fake-module1", "fake-module2", "fake-module3", "MODULES-IN-0-1"},
}, {
- description: "build file in 2nd level parent directory",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/Android.bp"},
- args: []string{},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"MODULES-IN-0"},
- expectedEnvVars: []envVar{},
+ description: "build file in 2nd level parent directory",
+ dirsInTrees: []string{"0/1/2"},
+ buildFiles: []string{"0/Android.bp"},
+ args: []string{},
+ curDir: "0/1/2",
+ tidyOnly: "",
+ expectedArgs: []string{"MODULES-IN-0"},
}, {
- description: "build action executed at root directory",
- dirsInTrees: []string{},
- buildFiles: []string{},
- rootSymlink: false,
- args: []string{},
- curDir: ".",
- tidyOnly: "",
- expectedArgs: []string{},
- expectedEnvVars: []envVar{},
+ description: "build action executed at root directory",
+ dirsInTrees: []string{},
+ buildFiles: []string{},
+ rootSymlink: false,
+ args: []string{},
+ curDir: ".",
+ tidyOnly: "",
+ expectedArgs: []string{},
}, {
- description: "build action executed at root directory in symlink",
- dirsInTrees: []string{},
- buildFiles: []string{},
- rootSymlink: true,
- args: []string{},
- curDir: ".",
- tidyOnly: "",
- expectedArgs: []string{},
- expectedEnvVars: []envVar{},
+ description: "build action executed at root directory in symlink",
+ dirsInTrees: []string{},
+ buildFiles: []string{},
+ rootSymlink: true,
+ args: []string{},
+ curDir: ".",
+ tidyOnly: "",
+ expectedArgs: []string{},
}, {
- description: "build file not found",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{},
- args: []string{},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"MODULES-IN-0-1-2"},
- expectedEnvVars: []envVar{},
- expectedErrStr: "Build file not found for 0/1/2 directory",
+ description: "build file not found",
+ dirsInTrees: []string{"0/1/2"},
+ buildFiles: []string{},
+ args: []string{},
+ curDir: "0/1/2",
+ tidyOnly: "",
+ expectedArgs: []string{"MODULES-IN-0-1-2"},
+ expectedErrStr: "Build file not found for 0/1/2 directory",
}, {
- description: "GET-INSTALL-PATH specified,",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/Android.mk"},
- args: []string{"GET-INSTALL-PATH", "-j", "-k", "GET-INSTALL-PATH"},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"-j", "-k", "GET-INSTALL-PATH-IN-0-1"},
- expectedEnvVars: []envVar{},
+ description: "GET-INSTALL-PATH specified,",
+ dirsInTrees: []string{"0/1/2"},
+ buildFiles: []string{"0/1/Android.mk"},
+ args: []string{"GET-INSTALL-PATH", "-j", "-k", "GET-INSTALL-PATH"},
+ curDir: "0/1/2",
+ tidyOnly: "",
+ expectedArgs: []string{"-j", "-k", "GET-INSTALL-PATH-IN-0-1"},
}, {
- description: "tidy only environment variable specified,",
- dirsInTrees: []string{"0/1/2"},
- buildFiles: []string{"0/1/Android.mk"},
- args: []string{"GET-INSTALL-PATH"},
- curDir: "0/1/2",
- tidyOnly: "true",
- expectedArgs: []string{"tidy_only"},
- expectedEnvVars: []envVar{},
+ description: "tidy only environment variable specified,",
+ dirsInTrees: []string{"0/1/2"},
+ buildFiles: []string{"0/1/Android.mk"},
+ args: []string{"GET-INSTALL-PATH"},
+ curDir: "0/1/2",
+ tidyOnly: "true",
+ expectedArgs: []string{"tidy_only"},
}, {
- description: "normal execution in root directory with args",
- dirsInTrees: []string{},
- buildFiles: []string{},
- args: []string{"-j", "-k", "fake_module"},
- curDir: "",
- tidyOnly: "",
- expectedArgs: []string{"-j", "-k", "fake_module"},
- expectedEnvVars: []envVar{},
+ description: "normal execution in root directory with args",
+ dirsInTrees: []string{},
+ buildFiles: []string{},
+ args: []string{"-j", "-k", "fake_module"},
+ curDir: "",
+ tidyOnly: "",
+ expectedArgs: []string{"-j", "-k", "fake_module"},
}}
for _, tt := range tests {
t.Run("build action BUILD_MODULES_IN_DIR, "+tt.description, func(t *testing.T) {
- testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY, true)
- })
- }
-}
-
-// TODO: Remove this test case once mmm shell build command has been deprecated.
-func TestGetConfigArgsBuildModulesInDirectoriesNoDeps(t *testing.T) {
- tests := []buildActionTestCase{{
- description: "normal execution in a directory",
- dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
- buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
- args: []string{"3.1/:t1,t2", "3.2/:t3,t4", "3.3/:t5,t6"},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"t1", "t2", "t3", "t4", "t5", "t6"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
- }, {
- description: "GET-INSTALL-PATH specified",
- dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
- buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
- args: []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3/:t6"},
- curDir: "0/1/2",
- tidyOnly: "",
- expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "t6"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
- }, {
- description: "tidy only environment variable specified",
- dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
- buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
- args: []string{"GET-INSTALL-PATH", "3.1/", "3.2/", "3.3/:t6"},
- curDir: "0/1/2",
- tidyOnly: "1",
- expectedArgs: []string{"tidy_only"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
- }, {
- description: "normal execution from top dir directory",
- dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
- buildFiles: []string{"0/1/2/3.1/Android.bp", "0/1/2/3.2/Android.bp", "0/1/2/3.3/Android.bp"},
- args: []string{"0/1/2/3.1", "0/1/2/3.2/:t3,t4", "0/1/2/3.3/:t5,t6"},
- curDir: ".",
- tidyOnly: "",
- expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "t3", "t4", "t5", "t6"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: "0/1/2/3.1/Android.mk 0/1/2/3.2/Android.mk 0/1/2/3.3/Android.mk"}},
- }}
- for _, tt := range tests {
- t.Run("build action BUILD_MODULES_IN_DIRS_NO_DEPS, "+tt.description, func(t *testing.T) {
- testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES, false)
+ testGetConfigArgs(t, tt, BUILD_MODULES_IN_A_DIRECTORY)
})
}
}
@@ -1132,10 +952,6 @@
curDir: "0/1/2",
tidyOnly: "",
expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-2-3.3"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: ""}},
}, {
description: "GET-INSTALL-PATH specified",
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3"},
@@ -1144,10 +960,6 @@
curDir: "0/1",
tidyOnly: "",
expectedArgs: []string{"GET-INSTALL-PATH-IN-0-1-2-3.1", "GET-INSTALL-PATH-IN-0-1-2-3.2", "GET-INSTALL-PATH-IN-0-1"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: ""}},
}, {
description: "tidy only environment variable specified",
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/2/3.3"},
@@ -1156,10 +968,6 @@
curDir: "0/1/2",
tidyOnly: "1",
expectedArgs: []string{"tidy_only"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: ""}},
}, {
description: "normal execution from top dir directory",
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
@@ -1169,10 +977,6 @@
curDir: ".",
tidyOnly: "",
expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: ""}},
}, {
description: "normal execution from top dir directory in symlink",
dirsInTrees: []string{"0/1/2/3.1", "0/1/2/3.2", "0/1/3", "0/2"},
@@ -1182,14 +986,10 @@
curDir: ".",
tidyOnly: "",
expectedArgs: []string{"MODULES-IN-0-1-2-3.1", "MODULES-IN-0-1-2-3.2", "MODULES-IN-0-1-3", "MODULES-IN-0-2"},
- expectedEnvVars: []envVar{
- envVar{
- name: "ONE_SHOT_MAKEFILE",
- value: ""}},
}}
for _, tt := range tests {
t.Run("build action BUILD_MODULES_IN_DIRS, "+tt.description, func(t *testing.T) {
- testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES, true)
+ testGetConfigArgs(t, tt, BUILD_MODULES_IN_DIRECTORIES)
})
}
}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 5ad966a..9ddbbea 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -42,9 +42,6 @@
if args := config.KatiArgs(); len(args) > 0 {
katiSuffix += "-" + spaceSlashReplacer.Replace(strings.Join(args, "_"))
}
- if oneShot, ok := config.Environment().Get("ONE_SHOT_MAKEFILE"); ok {
- katiSuffix += "-" + spaceSlashReplacer.Replace(oneShot)
- }
// If the suffix is too long, replace it with a md5 hash and write a
// file that contains the original suffix.