Merge changes Ib7ad715d,I3a83b5ed
* changes:
Remove frameworkResModule from sdkCorePlatform.
Remove the concept of useDefaultLibs from Soong.
diff --git a/Android.bp b/Android.bp
index 0b44198..3075d67 100644
--- a/Android.bp
+++ b/Android.bp
@@ -106,15 +106,24 @@
},
arm64: {
src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
- repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
+ repack_objects_to_keep: [
+ "unwind-dw2.o",
+ "unwind-dw2-fde-dip.o",
+ ],
},
x86: {
src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
- repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
+ repack_objects_to_keep: [
+ "unwind-dw2.o",
+ "unwind-dw2-fde-dip.o",
+ ],
},
x86_64: {
src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
- repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
+ repack_objects_to_keep: [
+ "unwind-dw2.o",
+ "unwind-dw2-fde-dip.o",
+ ],
},
},
}
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 928ca03..ff85661 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,3 @@
[Builtin Hooks]
gofmt = true
+bpfmt = true
diff --git a/android/androidmk.go b/android/androidmk.go
index d579e30..045cb59 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -46,7 +46,7 @@
type AndroidMkData struct {
Class string
SubName string
- DistFile OptionalPath
+ DistFiles TaggedDistFiles
OutputFile OptionalPath
Disabled bool
Include string
@@ -58,7 +58,7 @@
Extra []AndroidMkExtraFunc
- preamble bytes.Buffer
+ Entries AndroidMkEntries
}
type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
@@ -72,7 +72,7 @@
type AndroidMkEntries struct {
Class string
SubName string
- DistFile OptionalPath
+ DistFiles TaggedDistFiles
OutputFile OptionalPath
Disabled bool
Include string
@@ -137,6 +137,96 @@
a.EntryMap[name] = append(a.EntryMap[name], value...)
}
+// Compute the list of Make strings to declare phone goals and dist-for-goals
+// calls from the module's dist and dists properties.
+func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string {
+ amod := mod.(Module).base()
+ name := amod.BaseModuleName()
+
+ var ret []string
+
+ availableTaggedDists := TaggedDistFiles{}
+ if a.DistFiles != nil && len(a.DistFiles[""]) > 0 {
+ availableTaggedDists = a.DistFiles
+ } else if a.OutputFile.Valid() {
+ availableTaggedDists = MakeDefaultDistFiles(a.OutputFile.Path())
+ }
+
+ // Iterate over this module's dist structs, merged from the dist and dists properties.
+ for _, dist := range amod.Dists() {
+ // Get the list of goals this dist should be enabled for. e.g. sdk, droidcore
+ goals := strings.Join(dist.Targets, " ")
+
+ // Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map"
+ var tag string
+ if dist.Tag == nil {
+ // If the dist struct does not specify a tag, use the default output files tag.
+ tag = ""
+ } else {
+ tag = *dist.Tag
+ }
+
+ // Get the paths of the output files to be dist'd, represented by the tag.
+ // Can be an empty list.
+ tagPaths := availableTaggedDists[tag]
+ if len(tagPaths) == 0 {
+ // Nothing to dist for this tag, continue to the next dist.
+ continue
+ }
+
+ if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) {
+ errorMessage := "Cannot apply dest/suffix for more than one dist " +
+ "file for %s goals in module %s. The list of dist files, " +
+ "which should have a single element, is:\n%s"
+ panic(fmt.Errorf(errorMessage, goals, name, tagPaths))
+ }
+
+ ret = append(ret, fmt.Sprintf(".PHONY: %s\n", goals))
+
+ // Create dist-for-goals calls for each path in the dist'd files.
+ for _, path := range tagPaths {
+ // It's possible that the Path is nil from errant modules. Be defensive here.
+ if path == nil {
+ tagName := "default" // for error message readability
+ if dist.Tag != nil {
+ tagName = *dist.Tag
+ }
+ panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name))
+ }
+
+ dest := filepath.Base(path.String())
+
+ if dist.Dest != nil {
+ var err error
+ if dest, err = validateSafePath(*dist.Dest); err != nil {
+ // This was checked in ModuleBase.GenerateBuildActions
+ panic(err)
+ }
+ }
+
+ if dist.Suffix != nil {
+ ext := filepath.Ext(dest)
+ suffix := *dist.Suffix
+ dest = strings.TrimSuffix(dest, ext) + suffix + ext
+ }
+
+ if dist.Dir != nil {
+ var err error
+ if dest, err = validateSafePath(*dist.Dir, dest); err != nil {
+ // This was checked in ModuleBase.GenerateBuildActions
+ panic(err)
+ }
+ }
+
+ ret = append(
+ ret,
+ fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", goals, path.String(), dest))
+ }
+ }
+
+ return ret
+}
+
func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) {
a.EntryMap = make(map[string][]string)
amod := mod.(Module).base()
@@ -149,42 +239,8 @@
a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...)
a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...)
- // Fill in the header part.
- if len(amod.commonProperties.Dist.Targets) > 0 {
- distFile := a.DistFile
- if !distFile.Valid() {
- distFile = a.OutputFile
- }
- if distFile.Valid() {
- dest := filepath.Base(distFile.String())
-
- if amod.commonProperties.Dist.Dest != nil {
- var err error
- if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil {
- // This was checked in ModuleBase.GenerateBuildActions
- panic(err)
- }
- }
-
- if amod.commonProperties.Dist.Suffix != nil {
- ext := filepath.Ext(dest)
- suffix := *amod.commonProperties.Dist.Suffix
- dest = strings.TrimSuffix(dest, ext) + suffix + ext
- }
-
- if amod.commonProperties.Dist.Dir != nil {
- var err error
- if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil {
- // This was checked in ModuleBase.GenerateBuildActions
- panic(err)
- }
- }
-
- goals := strings.Join(amod.commonProperties.Dist.Targets, " ")
- fmt.Fprintln(&a.header, ".PHONY:", goals)
- fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n",
- goals, distFile.String(), dest)
- }
+ for _, distString := range a.GetDistForGoals(mod) {
+ fmt.Fprintf(&a.header, distString)
}
fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)")
@@ -427,10 +483,10 @@
func (data *AndroidMkData) fillInData(config Config, bpPath string, mod blueprint.Module) {
// Get the preamble content through AndroidMkEntries logic.
- entries := AndroidMkEntries{
+ data.Entries = AndroidMkEntries{
Class: data.Class,
SubName: data.SubName,
- DistFile: data.DistFile,
+ DistFiles: data.DistFiles,
OutputFile: data.OutputFile,
Disabled: data.Disabled,
Include: data.Include,
@@ -438,16 +494,12 @@
Host_required: data.Host_required,
Target_required: data.Target_required,
}
- entries.fillInEntries(config, bpPath, mod)
-
- // preamble doesn't need the footer content.
- entries.footer = bytes.Buffer{}
- entries.write(&data.preamble)
+ data.Entries.fillInEntries(config, bpPath, mod)
// copy entries back to data since it is used in Custom
- data.Required = entries.Required
- data.Host_required = entries.Host_required
- data.Target_required = entries.Target_required
+ data.Required = data.Entries.Required
+ data.Host_required = data.Entries.Host_required
+ data.Target_required = data.Entries.Target_required
}
func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
@@ -503,7 +555,9 @@
return
}
- w.Write(data.preamble.Bytes())
+ // write preamble via Entries
+ data.Entries.footer = bytes.Buffer{}
+ data.Entries.write(w)
for _, extra := range data.Extra {
extra(w, data.OutputFile.Path())
diff --git a/android/androidmk_test.go b/android/androidmk_test.go
index 71f8020..250f086 100644
--- a/android/androidmk_test.go
+++ b/android/androidmk_test.go
@@ -15,6 +15,7 @@
package android
import (
+ "fmt"
"io"
"reflect"
"testing"
@@ -22,10 +23,12 @@
type customModule struct {
ModuleBase
- data AndroidMkData
+ data AndroidMkData
+ distFiles TaggedDistFiles
}
func (m *customModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ m.distFiles = m.GenerateTaggedDistFiles(ctx)
}
func (m *customModule) AndroidMk() AndroidMkData {
@@ -36,6 +39,26 @@
}
}
+func (m *customModule) OutputFiles(tag string) (Paths, error) {
+ switch tag {
+ case "":
+ return PathsForTesting("one.out"), nil
+ case ".multiple":
+ return PathsForTesting("two.out", "three/four.out"), nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
+func (m *customModule) AndroidMkEntries() []AndroidMkEntries {
+ return []AndroidMkEntries{
+ {
+ Class: "CUSTOM_MODULE",
+ DistFiles: m.distFiles,
+ },
+ }
+}
+
func customModuleFactory() Module {
module := &customModule{}
InitAndroidModule(module)
@@ -76,3 +99,159 @@
assertEqual([]string{"baz"}, m.data.Host_required)
assertEqual([]string{"qux"}, m.data.Target_required)
}
+
+func TestGetDistForGoals(t *testing.T) {
+ testCases := []struct {
+ bp string
+ expectedAndroidMkLines []string
+ }{
+ {
+ bp: `
+ custom {
+ name: "foo",
+ dist: {
+ targets: ["my_goal"]
+ }
+ }
+ `,
+ expectedAndroidMkLines: []string{
+ ".PHONY: my_goal\n",
+ "$(call dist-for-goals,my_goal,one.out:one.out)\n",
+ },
+ },
+ {
+ bp: `
+ custom {
+ name: "foo",
+ dists: [
+ {
+ targets: ["my_goal"],
+ },
+ {
+ targets: ["my_second_goal", "my_third_goal"],
+ },
+ ],
+ }
+ `,
+ expectedAndroidMkLines: []string{
+ ".PHONY: my_goal\n",
+ "$(call dist-for-goals,my_goal,one.out:one.out)\n",
+ ".PHONY: my_second_goal my_third_goal\n",
+ "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n",
+ },
+ },
+ {
+ bp: `
+ custom {
+ name: "foo",
+ dist: {
+ targets: ["my_goal"],
+ },
+ dists: [
+ {
+ targets: ["my_second_goal", "my_third_goal"],
+ },
+ ],
+ }
+ `,
+ expectedAndroidMkLines: []string{
+ ".PHONY: my_second_goal my_third_goal\n",
+ "$(call dist-for-goals,my_second_goal my_third_goal,one.out:one.out)\n",
+ ".PHONY: my_goal\n",
+ "$(call dist-for-goals,my_goal,one.out:one.out)\n",
+ },
+ },
+ {
+ bp: `
+ custom {
+ name: "foo",
+ dist: {
+ targets: ["my_goal", "my_other_goal"],
+ tag: ".multiple",
+ },
+ dists: [
+ {
+ targets: ["my_second_goal"],
+ tag: ".multiple",
+ },
+ {
+ targets: ["my_third_goal"],
+ dir: "test/dir",
+ },
+ {
+ targets: ["my_fourth_goal"],
+ suffix: ".suffix",
+ },
+ {
+ targets: ["my_fifth_goal"],
+ dest: "new-name",
+ },
+ {
+ targets: ["my_sixth_goal"],
+ dest: "new-name",
+ dir: "some/dir",
+ suffix: ".suffix",
+ },
+ ],
+ }
+ `,
+ expectedAndroidMkLines: []string{
+ ".PHONY: my_second_goal\n",
+ "$(call dist-for-goals,my_second_goal,two.out:two.out)\n",
+ "$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n",
+ ".PHONY: my_third_goal\n",
+ "$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n",
+ ".PHONY: my_fourth_goal\n",
+ "$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n",
+ ".PHONY: my_fifth_goal\n",
+ "$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n",
+ ".PHONY: my_sixth_goal\n",
+ "$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n",
+ ".PHONY: my_goal my_other_goal\n",
+ "$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n",
+ "$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n",
+ },
+ },
+ }
+
+ for _, testCase := range testCases {
+ config := TestConfig(buildDir, nil, testCase.bp, nil)
+ config.inMake = true // Enable androidmk Singleton
+
+ ctx := NewTestContext()
+ ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
+ ctx.RegisterModuleType("custom", customModuleFactory)
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(t, errs)
+
+ module := ctx.ModuleForTests("foo", "").Module().(*customModule)
+ entries := AndroidMkEntriesForTest(t, config, "", module)
+ if len(entries) != 1 {
+ t.Errorf("Expected a single AndroidMk entry, got %d", len(entries))
+ }
+ androidMkLines := entries[0].GetDistForGoals(module)
+
+ if len(androidMkLines) != len(testCase.expectedAndroidMkLines) {
+ t.Errorf(
+ "Expected %d AndroidMk lines, got %d:\n%v",
+ len(testCase.expectedAndroidMkLines),
+ len(androidMkLines),
+ androidMkLines,
+ )
+ }
+ for idx, line := range androidMkLines {
+ expectedLine := testCase.expectedAndroidMkLines[idx]
+ if line != expectedLine {
+ t.Errorf(
+ "Expected AndroidMk line to be '%s', got '%s'",
+ line,
+ expectedLine,
+ )
+ }
+ }
+ }
+}
diff --git a/android/apex.go b/android/apex.go
index 30152db..47f07ca 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -124,6 +124,10 @@
// the private part of the listed APEXes even when it is not included in the
// APEXes.
TestFor() []string
+
+ // Returns nil if this module supports sdkVersion
+ // Otherwise, returns error with reason
+ ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion int) error
}
type ApexProperties struct {
@@ -477,3 +481,125 @@
},
})
}
+
+// TODO(b/158059172): remove minSdkVersion allowlist
+var minSdkVersionAllowlist = map[string]int{
+ "adbd": 30,
+ "android.net.ipsec.ike": 30,
+ "androidx-constraintlayout_constraintlayout-solver": 30,
+ "androidx.annotation_annotation": 28,
+ "androidx.arch.core_core-common": 28,
+ "androidx.collection_collection": 28,
+ "androidx.lifecycle_lifecycle-common": 28,
+ "apache-commons-compress": 29,
+ "bouncycastle_ike_digests": 30,
+ "brotli-java": 29,
+ "captiveportal-lib": 28,
+ "flatbuffer_headers": 30,
+ "framework-permission": 30,
+ "framework-statsd": 30,
+ "gemmlowp_headers": 30,
+ "ike-internals": 30,
+ "kotlinx-coroutines-android": 28,
+ "kotlinx-coroutines-core": 28,
+ "libadb_crypto": 30,
+ "libadb_pairing_auth": 30,
+ "libadb_pairing_connection": 30,
+ "libadb_pairing_server": 30,
+ "libadb_protos": 30,
+ "libadb_tls_connection": 30,
+ "libadbconnection_client": 30,
+ "libadbconnection_server": 30,
+ "libadbd_core": 30,
+ "libadbd_services": 30,
+ "libadbd": 30,
+ "libapp_processes_protos_lite": 30,
+ "libasyncio": 30,
+ "libbrotli": 30,
+ "libbuildversion": 30,
+ "libcrypto_static": 30,
+ "libcrypto_utils": 30,
+ "libdiagnose_usb": 30,
+ "libeigen": 30,
+ "liblz4": 30,
+ "libmdnssd": 30,
+ "libneuralnetworks_common": 30,
+ "libneuralnetworks_headers": 30,
+ "libneuralnetworks": 30,
+ "libprocpartition": 30,
+ "libprotobuf-java-lite": 30,
+ "libprotoutil": 30,
+ "libqemu_pipe": 30,
+ "libstats_jni": 30,
+ "libstatslog_statsd": 30,
+ "libstatsmetadata": 30,
+ "libstatspull": 30,
+ "libstatssocket": 30,
+ "libsync": 30,
+ "libtextclassifier_hash_headers": 30,
+ "libtextclassifier_hash_static": 30,
+ "libtflite_kernel_utils": 30,
+ "libwatchdog": 29,
+ "libzstd": 30,
+ "metrics-constants-protos": 28,
+ "net-utils-framework-common": 29,
+ "permissioncontroller-statsd": 28,
+ "philox_random_headers": 30,
+ "philox_random": 30,
+ "service-permission": 30,
+ "service-statsd": 30,
+ "statsd-aidl-ndk_platform": 30,
+ "statsd": 30,
+ "tensorflow_headers": 30,
+ "xz-java": 29,
+}
+
+// Function called while walking an APEX's payload dependencies.
+//
+// Return true if the `to` module should be visited, false otherwise.
+type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
+
+// UpdatableModule represents updatable APEX/APK
+type UpdatableModule interface {
+ Module
+ WalkPayloadDeps(ctx ModuleContext, do PayloadDepsCallback)
+}
+
+// CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version accordingly
+func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion int) {
+ // do not enforce min_sdk_version for host
+ if ctx.Host() {
+ return
+ }
+
+ // do not enforce for coverage build
+ if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled() {
+ return
+ }
+
+ // do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version or
+ // min_sdk_version is not finalized (e.g. current or codenames)
+ if minSdkVersion == FutureApiLevel {
+ return
+ }
+
+ m.WalkPayloadDeps(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
+ if externalDep {
+ // external deps are outside the payload boundary, which is "stable" interface.
+ // We don't have to check min_sdk_version for external dependencies.
+ return false
+ }
+ if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+ return false
+ }
+ if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
+ toName := ctx.OtherModuleName(to)
+ if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver > minSdkVersion {
+ ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v. Dependency path: %s",
+ minSdkVersion, ctx.ModuleName(), err.Error(), ctx.GetPathString(false))
+ return false
+ }
+ }
+ return true
+ })
+}
diff --git a/android/config.go b/android/config.go
index b906108..6f73a12 100644
--- a/android/config.go
+++ b/android/config.go
@@ -406,6 +406,14 @@
return Config{}, err
}
+ if Bool(config.productVariables.GcovCoverage) && Bool(config.productVariables.ClangCoverage) {
+ return Config{}, fmt.Errorf("GcovCoverage and ClangCoverage cannot both be set")
+ }
+
+ config.productVariables.Native_coverage = proptools.BoolPtr(
+ Bool(config.productVariables.GcovCoverage) ||
+ Bool(config.productVariables.ClangCoverage))
+
return Config{config}, nil
}
@@ -1044,7 +1052,7 @@
// represents any path.
func (c *deviceConfig) JavaCoverageEnabledForPath(path string) bool {
coverage := false
- if c.config.productVariables.JavaCoveragePaths == nil ||
+ if len(c.config.productVariables.JavaCoveragePaths) == 0 ||
InList("*", c.config.productVariables.JavaCoveragePaths) ||
HasAnyPrefix(path, c.config.productVariables.JavaCoveragePaths) {
coverage = true
@@ -1057,18 +1065,20 @@
return coverage
}
-func (c *config) NativeLineCoverage() bool {
- return Bool(c.productVariables.NativeLineCoverage)
-}
-
+// Returns true if gcov or clang coverage is enabled.
func (c *deviceConfig) NativeCoverageEnabled() bool {
- return Bool(c.config.productVariables.Native_coverage) || Bool(c.config.productVariables.NativeLineCoverage)
+ return Bool(c.config.productVariables.GcovCoverage) ||
+ Bool(c.config.productVariables.ClangCoverage)
}
func (c *deviceConfig) ClangCoverageEnabled() bool {
return Bool(c.config.productVariables.ClangCoverage)
}
+func (c *deviceConfig) GcovCoverageEnabled() bool {
+ return Bool(c.config.productVariables.GcovCoverage)
+}
+
// NativeCoverageEnabledForPath returns whether (GCOV- or Clang-based) native
// code coverage is enabled for path. By default, coverage is not enabled for a
// given path unless it is part of the NativeCoveragePaths product variable (and
diff --git a/android/hooks.go b/android/hooks.go
index f43a007..85fc081 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -120,6 +120,7 @@
type InstallHookContext interface {
ModuleContext
+ SrcPath() Path
Path() InstallPath
Symlink() bool
}
@@ -134,10 +135,17 @@
type installHookContext struct {
ModuleContext
+ srcPath Path
path InstallPath
symlink bool
}
+var _ InstallHookContext = &installHookContext{}
+
+func (x *installHookContext) SrcPath() Path {
+ return x.srcPath
+}
+
func (x *installHookContext) Path() InstallPath {
return x.path
}
@@ -146,10 +154,11 @@
return x.symlink
}
-func (x *hooks) runInstallHooks(ctx ModuleContext, path InstallPath, symlink bool) {
+func (x *hooks) runInstallHooks(ctx ModuleContext, srcPath Path, path InstallPath, symlink bool) {
if len(x.install) > 0 {
mctx := &installHookContext{
ModuleContext: ctx,
+ srcPath: srcPath,
path: path,
symlink: symlink,
}
diff --git a/android/module.go b/android/module.go
index f24047c..06079ca 100644
--- a/android/module.go
+++ b/android/module.go
@@ -315,6 +315,28 @@
return qualifiedModuleName{pkg: pkg, name: ""}
}
+type Dist struct {
+ // Copy the output of this module to the $DIST_DIR when `dist` is specified on the
+ // command line and any of these targets are also on the command line, or otherwise
+ // built
+ Targets []string `android:"arch_variant"`
+
+ // The name of the output artifact. This defaults to the basename of the output of
+ // the module.
+ Dest *string `android:"arch_variant"`
+
+ // The directory within the dist directory to store the artifact. Defaults to the
+ // top level directory ("").
+ Dir *string `android:"arch_variant"`
+
+ // A suffix to add to the artifact file name (before any extension).
+ Suffix *string `android:"arch_variant"`
+
+ // A string tag to select the OutputFiles associated with the tag. Defaults to the
+ // the empty "" string.
+ Tag *string `android:"arch_variant"`
+}
+
type nameProperties struct {
// The name of the module. Must be unique across all modules.
Name *string
@@ -454,23 +476,13 @@
// relative path to a file to include in the list of notices for the device
Notice *string `android:"path"`
- Dist struct {
- // copy the output of this module to the $DIST_DIR when `dist` is specified on the
- // command line and any of these targets are also on the command line, or otherwise
- // built
- Targets []string `android:"arch_variant"`
+ // configuration to distribute output files from this module to the distribution
+ // directory (default: $OUT/dist, configurable with $DIST_DIR)
+ Dist Dist `android:"arch_variant"`
- // The name of the output artifact. This defaults to the basename of the output of
- // the module.
- Dest *string `android:"arch_variant"`
-
- // The directory within the dist directory to store the artifact. Defaults to the
- // top level directory ("").
- Dir *string `android:"arch_variant"`
-
- // A suffix to add to the artifact file name (before any extension).
- Suffix *string `android:"arch_variant"`
- } `android:"arch_variant"`
+ // a list of configurations to distribute output files from this module to the
+ // distribution directory (default: $OUT/dist, configurable with $DIST_DIR)
+ Dists []Dist `android:"arch_variant"`
// The OsType of artifacts that this module variant is responsible for creating.
//
@@ -537,6 +549,14 @@
ImageVariation string `blueprint:"mutated"`
}
+// A map of OutputFile tag keys to Paths, for disting purposes.
+type TaggedDistFiles map[string]Paths
+
+func MakeDefaultDistFiles(paths ...Path) TaggedDistFiles {
+ // The default OutputFile tag is the empty "" string.
+ return TaggedDistFiles{"": paths}
+}
+
type hostAndDeviceProperties struct {
// If set to true, build a variant of the module for the host. Defaults to false.
Host_supported *bool
@@ -815,6 +835,41 @@
return m.visibilityPropertyInfo
}
+func (m *ModuleBase) Dists() []Dist {
+ if len(m.commonProperties.Dist.Targets) > 0 {
+ // Make a copy of the underlying Dists slice to protect against
+ // backing array modifications with repeated calls to this method.
+ distsCopy := append([]Dist(nil), m.commonProperties.Dists...)
+ return append(distsCopy, m.commonProperties.Dist)
+ } else {
+ return m.commonProperties.Dists
+ }
+}
+
+func (m *ModuleBase) GenerateTaggedDistFiles(ctx BaseModuleContext) TaggedDistFiles {
+ distFiles := make(TaggedDistFiles)
+ for _, dist := range m.Dists() {
+ var tag string
+ var distFilesForTag Paths
+ if dist.Tag == nil {
+ tag = ""
+ } else {
+ tag = *dist.Tag
+ }
+ distFilesForTag, err := m.base().module.(OutputFileProducer).OutputFiles(tag)
+ if err != nil {
+ ctx.PropertyErrorf("dist.tag", "%s", err.Error())
+ }
+ for _, distFile := range distFilesForTag {
+ if distFile != nil && !distFiles[tag].containsPath(distFile) {
+ distFiles[tag] = append(distFiles[tag], distFile)
+ }
+ }
+ }
+
+ return distFiles
+}
+
func (m *ModuleBase) Target() Target {
return m.commonProperties.CompileTarget
}
@@ -1959,7 +2014,7 @@
rule blueprint.Rule, deps []Path) InstallPath {
fullInstallPath := installPath.Join(m, name)
- m.module.base().hooks.runInstallHooks(m, fullInstallPath, false)
+ m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
if !m.skipInstall(fullInstallPath) {
@@ -1993,7 +2048,7 @@
func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath {
fullInstallPath := installPath.Join(m, name)
- m.module.base().hooks.runInstallHooks(m, fullInstallPath, true)
+ m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true)
if !m.skipInstall(fullInstallPath) {
@@ -2022,7 +2077,7 @@
// (e.g. /apex/...)
func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath {
fullInstallPath := installPath.Join(m, name)
- m.module.base().hooks.runInstallHooks(m, fullInstallPath, true)
+ m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
if !m.skipInstall(fullInstallPath) {
m.Build(pctx, BuildParams{
diff --git a/android/neverallow.go b/android/neverallow.go
index 26e42e6..526d399 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -145,11 +145,18 @@
"prebuilts",
}
- // Core library constraints. The sdk_version: "none" can only be used in core library projects.
+ // Additional whitelisted path only used for ART testing, which needs access to core library
+ // targets. This does not affect the contents of a device image (system, vendor, etc.).
+ var artTests = []string{
+ "art/test",
+ }
+
+ // Core library constraints. The sdk_version: "none" can only be used in core library projects and ART tests.
// Access to core library targets is restricted using visibility rules.
rules := []Rule{
NeverAllow().
NotIn(coreLibraryProjects...).
+ NotIn(artTests...).
With("sdk_version", "none").
WithoutMatcher("name", Regexp("^android_.*stubs_current$")),
}
diff --git a/android/override_module.go b/android/override_module.go
index 7e58890..6b246db 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -42,6 +42,11 @@
setOverridingProperties(properties []interface{})
getOverrideModuleProperties() *OverrideModuleProperties
+
+ // Internal funcs to handle interoperability between override modules and prebuilts.
+ // i.e. cases where an overriding module, too, is overridden by a prebuilt module.
+ setOverriddenByPrebuilt(overridden bool)
+ getOverriddenByPrebuilt() bool
}
// Base module struct for override module types
@@ -49,6 +54,8 @@
moduleProperties OverrideModuleProperties
overridingProperties []interface{}
+
+ overriddenByPrebuilt bool
}
type OverrideModuleProperties struct {
@@ -74,6 +81,14 @@
return proptools.String(o.moduleProperties.Base)
}
+func (o *OverrideModuleBase) setOverriddenByPrebuilt(overridden bool) {
+ o.overriddenByPrebuilt = overridden
+}
+
+func (o *OverrideModuleBase) getOverriddenByPrebuilt() bool {
+ return o.overriddenByPrebuilt
+}
+
func InitOverrideModule(m OverrideModule) {
m.setOverridingProperties(m.GetProperties())
@@ -208,21 +223,24 @@
// next phase.
func overrideModuleDepsMutator(ctx BottomUpMutatorContext) {
if module, ok := ctx.Module().(OverrideModule); ok {
- // Skip this overriding module if there's a prebuilt module that overrides it with prefer flag.
- overriddenByPrebuilt := false
+ base := String(module.getOverrideModuleProperties().Base)
+ if !ctx.OtherModuleExists(base) {
+ ctx.PropertyErrorf("base", "%q is not a valid module name", base)
+ return
+ }
+ // See if there's a prebuilt module that overrides this override module with prefer flag,
+ // in which case we call SkipInstall on the corresponding variant later.
ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(dep Module) {
prebuilt, ok := dep.(PrebuiltInterface)
if !ok {
panic("PrebuiltDepTag leads to a non-prebuilt module " + dep.Name())
}
if prebuilt.Prebuilt().UsePrebuilt() {
- overriddenByPrebuilt = true
+ module.setOverriddenByPrebuilt(true)
return
}
})
- if !overriddenByPrebuilt {
- ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base)
- }
+ ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base)
}
}
@@ -258,6 +276,10 @@
ctx.AliasVariation(variants[0])
for i, o := range overrides {
mods[i+1].(OverridableModule).override(ctx, o)
+ if o.getOverriddenByPrebuilt() {
+ // The overriding module itself, too, is overridden by a prebuilt. Skip its installation.
+ mods[i+1].SkipInstall()
+ }
}
} else if o, ok := ctx.Module().(OverrideModule); ok {
// Create a variant of the overriding module with its own name. This matches the above local
diff --git a/android/paths.go b/android/paths.go
index bed6f3f..d8d51a7 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -220,6 +220,15 @@
// Paths is a slice of Path objects, with helpers to operate on the collection.
type Paths []Path
+func (paths Paths) containsPath(path Path) bool {
+ for _, p := range paths {
+ if p == path {
+ return true
+ }
+ }
+ return false
+}
+
// PathsForSource returns Paths rooted from SrcDir
func PathsForSource(ctx PathContext, paths []string) Paths {
ret := make(Paths, len(paths))
diff --git a/android/variable.go b/android/variable.go
index b2149c3..2c8bd07 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -270,12 +270,14 @@
JavaCoveragePaths []string `json:",omitempty"`
JavaCoverageExcludePaths []string `json:",omitempty"`
- NativeLineCoverage *bool `json:",omitempty"`
- Native_coverage *bool `json:",omitempty"`
+ GcovCoverage *bool `json:",omitempty"`
ClangCoverage *bool `json:",omitempty"`
NativeCoveragePaths []string `json:",omitempty"`
NativeCoverageExcludePaths []string `json:",omitempty"`
+ // Set by NewConfig
+ Native_coverage *bool
+
SanitizeHost []string `json:",omitempty"`
SanitizeDevice []string `json:",omitempty"`
SanitizeDeviceDiag []string `json:",omitempty"`
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index 4aadbe8..03cf74d 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -34,6 +34,7 @@
defs []bpparser.Definition
localAssignments map[string]*bpparser.Property
globalAssignments map[string]*bpparser.Expression
+ variableRenames map[string]string
scope mkparser.Scope
module *bpparser.Module
@@ -43,6 +44,10 @@
inModule bool
}
+var invalidVariableStringToReplacement = map[string]string{
+ "-": "_dash_",
+}
+
func (f *bpFile) insertComment(s string) {
f.comments = append(f.comments, &bpparser.CommentGroup{
Comments: []*bpparser.Comment{
@@ -120,6 +125,7 @@
scope: androidScope(),
localAssignments: make(map[string]*bpparser.Property),
globalAssignments: make(map[string]*bpparser.Expression),
+ variableRenames: make(map[string]string),
}
var conds []*conditional
@@ -224,6 +230,25 @@
return string(out), errs
}
+func renameVariableWithInvalidCharacters(name string) string {
+ renamed := ""
+ for invalid, replacement := range invalidVariableStringToReplacement {
+ if strings.Contains(name, invalid) {
+ renamed = strings.ReplaceAll(name, invalid, replacement)
+ }
+ }
+
+ return renamed
+}
+
+func invalidVariableStrings() string {
+ invalidStrings := make([]string, 0, len(invalidVariableStringToReplacement))
+ for s := range invalidVariableStringToReplacement {
+ invalidStrings = append(invalidStrings, "\""+s+"\"")
+ }
+ return strings.Join(invalidStrings, ", ")
+}
+
func handleAssignment(file *bpFile, assignment *mkparser.Assignment, c *conditional) {
if !assignment.Name.Const() {
file.errorf(assignment, "unsupported non-const variable name")
@@ -238,6 +263,12 @@
name := assignment.Name.Value(nil)
prefix := ""
+ if newName := renameVariableWithInvalidCharacters(name); newName != "" {
+ file.warnf("Variable names cannot contain: %s. Renamed \"%s\" to \"%s\"", invalidVariableStrings(), name, newName)
+ file.variableRenames[name] = newName
+ name = newName
+ }
+
if strings.HasPrefix(name, "LOCAL_") {
for _, x := range propertyPrefixes {
if strings.HasSuffix(name, "_"+x.mk) {
@@ -341,11 +372,11 @@
var err error
switch typ {
case bpparser.ListType:
- exp, err = makeToListExpression(val, file.scope)
+ exp, err = makeToListExpression(val, file)
case bpparser.StringType:
- exp, err = makeToStringExpression(val, file.scope)
+ exp, err = makeToStringExpression(val, file)
case bpparser.BoolType:
- exp, err = makeToBoolExpression(val)
+ exp, err = makeToBoolExpression(val, file)
default:
panic("unknown type")
}
@@ -358,7 +389,6 @@
}
func setVariable(file *bpFile, plusequals bool, prefix, name string, value bpparser.Expression, local bool) error {
-
if prefix != "" {
name = prefix + "." + name
}
@@ -428,6 +458,9 @@
}
file.defs = append(file.defs, a)
} else {
+ if _, ok := file.globalAssignments[name]; ok {
+ return fmt.Errorf("cannot assign a variable multiple times: \"%s\"", name)
+ }
a := &bpparser.Assignment{
Name: name,
NamePos: pos,
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 54bd586..2448acc 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -876,7 +876,7 @@
prebuilt_etc {
name: "etc.test1",
src: "mymod",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
}
`,
@@ -896,7 +896,7 @@
name: "etc.test1",
src: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
}
`,
@@ -913,7 +913,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
device_specific: true,
}
@@ -931,7 +931,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
product_specific: true,
@@ -950,7 +950,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
product_specific: true,
}
@@ -968,7 +968,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
system_ext_specific: true,
}
@@ -986,7 +986,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
system_ext_specific: true,
@@ -1005,7 +1005,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
proprietary: true,
}
@@ -1023,7 +1023,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
proprietary: true,
}
@@ -1041,7 +1041,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
proprietary: true,
}
@@ -1059,7 +1059,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
recovery: true,
}
@@ -1098,7 +1098,7 @@
name: "foo",
src: "foo.txt",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1174,7 +1174,7 @@
name: "foo",
src: "foo.txt",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1193,7 +1193,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1212,7 +1212,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1231,7 +1231,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
proprietary: true,
}
`,
@@ -1251,7 +1251,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
proprietary: true,
}
`,
@@ -1367,6 +1367,57 @@
`,
},
{
+ desc: "dashed_variable gets renamed",
+ in: `
+ include $(CLEAR_VARS)
+
+ dashed-variable:= a.cpp
+
+ LOCAL_MODULE:= test
+ LOCAL_SRC_FILES:= $(dashed-variable)
+ include $(BUILD_EXECUTABLE)
+ `,
+ expected: `
+
+// ANDROIDMK TRANSLATION WARNING: Variable names cannot contain: "-". Renamed "dashed-variable" to "dashed_dash_variable"
+dashed_dash_variable = ["a.cpp"]
+cc_binary {
+
+ name: "test",
+ srcs: dashed_dash_variable,
+}
+`,
+ },
+ {
+ desc: "variableReassigned",
+ in: `
+include $(CLEAR_VARS)
+
+src_files:= a.cpp
+
+LOCAL_SRC_FILES:= $(src_files)
+LOCAL_MODULE:= test
+include $(BUILD_EXECUTABLE)
+
+# clear locally used variable
+src_files:=
+`,
+ expected: `
+
+
+src_files = ["a.cpp"]
+cc_binary {
+ name: "test",
+
+ srcs: src_files,
+}
+
+// clear locally used variable
+// ANDROIDMK TRANSLATION ERROR: cannot assign a variable multiple times: "src_files"
+// src_files :=
+`,
+ },
+ {
desc: "undefined_boolean_var",
in: `
include $(CLEAR_VARS)
diff --git a/androidmk/androidmk/values.go b/androidmk/androidmk/values.go
index 6b18a65..9618142 100644
--- a/androidmk/androidmk/values.go
+++ b/androidmk/androidmk/values.go
@@ -60,8 +60,7 @@
}, nil
}
-func makeToStringExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToStringExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
var val bpparser.Expression
var err error
@@ -70,18 +69,18 @@
}
for i, s := range ms.Strings[1:] {
- if ret, ok := ms.Variables[i].EvalFunction(scope); ok {
+ if ret, ok := ms.Variables[i].EvalFunction(file.scope); ok {
if len(ret) > 1 {
return nil, fmt.Errorf("Unexpected list value %s", ms.Dump())
}
val, err = addValues(val, stringToStringValue(ret[0]))
} else {
- name := ms.Variables[i].Name
- if !name.Const() {
- return nil, fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+ name, err := extractVariableName(ms.Variables[i].Name, file)
+ if err != nil {
+ return nil, err
}
tmp := &bpparser.Variable{
- Name: name.Value(nil),
+ Name: name,
Value: &bpparser.String{},
}
@@ -125,8 +124,7 @@
}
-func makeToListExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToListExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
fields := ms.Split(" \t")
var listOfListValues []bpparser.Expression
@@ -135,14 +133,14 @@
for _, f := range fields {
if len(f.Variables) == 1 && f.Strings[0] == "" && f.Strings[1] == "" {
- if ret, ok := f.Variables[0].EvalFunction(scope); ok {
+ if ret, ok := f.Variables[0].EvalFunction(file.scope); ok {
listValue.Values = append(listValue.Values, stringListToStringValueList(ret)...)
} else {
- // Variable by itself, variable is probably a list
- if !f.Variables[0].Name.Const() {
- return nil, fmt.Errorf("unsupported non-const variable name")
+ name, err := extractVariableName(f.Variables[0].Name, file)
+ if err != nil {
+ return nil, err
}
- if f.Variables[0].Name.Value(nil) == "TOP" {
+ if name == "TOP" {
listValue.Values = append(listValue.Values, &bpparser.String{
Value: ".",
})
@@ -151,14 +149,14 @@
listOfListValues = append(listOfListValues, listValue)
}
listOfListValues = append(listOfListValues, &bpparser.Variable{
- Name: f.Variables[0].Name.Value(nil),
+ Name: name,
Value: &bpparser.List{},
})
listValue = &bpparser.List{}
}
}
} else {
- s, err := makeToStringExpression(f, scope)
+ s, err := makeToStringExpression(f, file)
if err != nil {
return nil, err
}
@@ -208,15 +206,15 @@
}, nil
}
-func makeToBoolExpression(ms *mkparser.MakeString) (bpparser.Expression, error) {
+func makeToBoolExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
if !ms.Const() {
if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
- name := ms.Variables[0].Name
- if !name.Const() {
- return nil, fmt.Errorf("unsupported non-const variable name")
+ name, err := extractVariableName(ms.Variables[0].Name, file)
+ if err != nil {
+ return nil, err
}
return &bpparser.Variable{
- Name: name.Value(nil),
+ Name: name,
Value: &bpparser.Bool{},
}, nil
} else {
@@ -226,3 +224,17 @@
return stringToBoolValue(ms.Value(nil))
}
+
+func extractVariableName(name *mkparser.MakeString, file *bpFile) (string, error) {
+ if !name.Const() {
+ return "", fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+ }
+
+ variableName := name.Value(nil)
+
+ if newName, ok := file.variableRenames[variableName]; ok {
+ variableName = newName
+ }
+
+ return variableName, nil
+}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 4dd14d8..7595238 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -33,14 +33,7 @@
Disabled: true,
}
}
- writers := []android.AndroidMkData{}
- writers = append(writers, a.androidMkForType())
- return android.AndroidMkData{
- Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- for _, data := range writers {
- data.Custom(w, name, prefix, moduleDir, data)
- }
- }}
+ return a.androidMkForType()
}
func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string) []string {
@@ -308,6 +301,20 @@
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
+
+ // Because apex writes .mk with Custom(), we need to write manually some common properties
+ // which are available via data.Entries
+ commonProperties := []string{
+ "LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+ "LOCAL_PROPRIETARY_MODULE", "LOCAL_VENDOR_MODULE", "LOCAL_ODM_MODULE", "LOCAL_PRODUCT_MODULE", "LOCAL_SYSTEM_EXT_MODULE",
+ "LOCAL_MODULE_OWNER",
+ }
+ for _, name := range commonProperties {
+ if value, ok := data.Entries.EntryMap[name]; ok {
+ fmt.Fprintln(w, name+" := "+strings.Join(value, " "))
+ }
+ }
+
if len(a.overridableProperties.Overrides) > 0 {
fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.overridableProperties.Overrides, " "))
}
diff --git a/apex/apex.go b/apex/apex.go
index a4af7aa..d0c1a09 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -16,7 +16,6 @@
import (
"fmt"
- "path"
"path/filepath"
"sort"
"strings"
@@ -369,7 +368,6 @@
"libbinderthreadstateutils",
"libbluetooth-types-header",
"libbufferhub_headers",
- "libc_scudo",
"libcodec2",
"libcodec2_headers",
"libcodec2_hidl@1.0",
@@ -985,9 +983,6 @@
// List of providing APEXes' names so that this APEX can depend on provided shared libraries.
Uses []string
- // A txt file containing list of files that are allowed to be included in this APEX.
- Allowed_files *string
-
// package format of this apex variant; could be non-flattened, flattened, or zip.
// imageApex, zipApex or flattened
ApexType apexPackaging `blueprint:"mutated"`
@@ -1063,6 +1058,9 @@
// Apex Container Package Name.
// Override value for attribute package:name in AndroidManifest.xml
Package_name string
+
+ // A txt file containing list of files that are allowed to be included in this APEX.
+ Allowed_files *string `android:"path"`
}
type apexPackaging int
@@ -1243,7 +1241,7 @@
container_certificate_file android.Path
container_private_key_file android.Path
- fileContexts android.Path
+ fileContexts android.WritablePath
// list of files to be included in this apex
filesInfo []apexFile
@@ -1331,6 +1329,7 @@
targets := ctx.MultiTargets()
config := ctx.DeviceConfig()
+ imageVariation := a.getImageVariation(ctx)
a.combineProperties(ctx)
@@ -1350,13 +1349,13 @@
Jni_libs: a.properties.Jni_libs,
Binaries: nil,
},
- target, a.getImageVariation(config))
+ target, imageVariation)
// Add native modules targetting both ABIs
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Both,
target,
- a.getImageVariation(config))
+ imageVariation)
isPrimaryAbi := i == 0
if isPrimaryAbi {
@@ -1369,13 +1368,13 @@
Jni_libs: nil,
Binaries: a.properties.Binaries,
},
- target, a.getImageVariation(config))
+ target, imageVariation)
// Add native modules targetting the first ABI
addDependenciesForNativeModules(ctx,
a.properties.Multilib.First,
target,
- a.getImageVariation(config))
+ imageVariation)
}
switch target.Arch.ArchType.Multilib {
@@ -1384,24 +1383,24 @@
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Lib32,
target,
- a.getImageVariation(config))
+ imageVariation)
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Prefer32,
target,
- a.getImageVariation(config))
+ imageVariation)
case "lib64":
// Add native modules targetting 64-bit ABI
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Lib64,
target,
- a.getImageVariation(config))
+ imageVariation)
if !has32BitTarget {
addDependenciesForNativeModules(ctx,
a.properties.Multilib.Prefer32,
target,
- a.getImageVariation(config))
+ imageVariation)
}
}
}
@@ -1454,6 +1453,9 @@
}
func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) {
+ if a.overridableProperties.Allowed_files != nil {
+ android.ExtractSourceDeps(ctx, a.overridableProperties.Allowed_files)
+ }
ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
androidAppTag, a.overridableProperties.Apps...)
ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
@@ -1500,15 +1502,33 @@
return proptools.Bool(a.properties.Test_only_unsigned_payload)
}
-func (a *apexBundle) getImageVariation(config android.DeviceConfig) string {
+func (a *apexBundle) getImageVariation(ctx android.BottomUpMutatorContext) string {
+ deviceConfig := ctx.DeviceConfig()
if a.vndkApex {
- return cc.VendorVariationPrefix + a.vndkVersion(config)
+ return cc.VendorVariationPrefix + a.vndkVersion(deviceConfig)
}
- if config.VndkVersion() != "" && proptools.Bool(a.properties.Use_vendor) {
- return cc.VendorVariationPrefix + config.PlatformVndkVersion()
- } else {
- return android.CoreVariation
+
+ var prefix string
+ var vndkVersion string
+ if deviceConfig.VndkVersion() != "" {
+ if proptools.Bool(a.properties.Use_vendor) {
+ prefix = cc.VendorVariationPrefix
+ vndkVersion = deviceConfig.PlatformVndkVersion()
+ } else if a.SocSpecific() || a.DeviceSpecific() {
+ prefix = cc.VendorVariationPrefix
+ vndkVersion = deviceConfig.VndkVersion()
+ } else if a.ProductSpecific() {
+ prefix = cc.ProductVariationPrefix
+ vndkVersion = deviceConfig.ProductVndkVersion()
+ }
}
+ if vndkVersion == "current" {
+ vndkVersion = deviceConfig.PlatformVndkVersion()
+ }
+ if vndkVersion != "" {
+ return prefix + vndkVersion
+ }
+ return android.CoreVariation
}
func (a *apexBundle) EnableSanitizer(sanitizerName string) {
@@ -1540,7 +1560,7 @@
for _, target := range ctx.MultiTargets() {
if target.Arch.ArchType.Multilib == "lib64" {
ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: a.getImageVariation(ctx.DeviceConfig())},
+ {Mutator: "image", Variation: a.getImageVariation(ctx)},
{Mutator: "link", Variation: "shared"},
{Mutator: "version", Variation: ""}, // "" is the non-stub variant
}...), sharedLibTag, "libclang_rt.hwasan-aarch64-android")
@@ -1553,7 +1573,7 @@
var _ cc.Coverage = (*apexBundle)(nil)
func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
- return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
+ return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
}
func (a *apexBundle) PreventInstall() {
@@ -1722,13 +1742,8 @@
return true
}
-// Function called while walking an APEX's payload dependencies.
-//
-// Return true if the `to` module should be visited, false otherwise.
-type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool
-
// Visit dependencies that contributes to the payload of this APEX
-func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) {
+func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
ctx.WalkDeps(func(child, parent android.Module) bool {
am, ok := child.(android.ApexModule)
if !ok || !am.CanHaveApexVariants() {
@@ -1754,7 +1769,21 @@
}
func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int {
- ver := proptools.StringDefault(a.properties.Min_sdk_version, "current")
+ ver := proptools.String(a.properties.Min_sdk_version)
+ if ver == "" {
+ return android.FutureApiLevel
+ }
+ // Treat the current codenames as "current", which means future API version (10000)
+ // Otherwise, ApiStrToNum converts codename(non-finalized) to a value from [9000...]
+ // and would fail to build against "current".
+ if android.InList(ver, ctx.Config().PlatformVersionActiveCodenames()) {
+ return android.FutureApiLevel
+ }
+ // In "REL" branch, "current" is mapped to finalized sdk version
+ if ctx.Config().PlatformSdkCodename() == "REL" && ver == "current" {
+ return ctx.Config().PlatformSdkVersionInt()
+ }
+ // Finalized codenames are OKAY and will be converted to int
intVer, err := android.ApiStrToNum(ctx, ver)
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
@@ -1775,6 +1804,12 @@
return
}
+ // Because APEXes targeting other than system/system_ext partitions
+ // can't set apex_available, we skip checks for these APEXes
+ if ctx.SocSpecific() || ctx.DeviceSpecific() || ctx.ProductSpecific() {
+ return
+ }
+
// Coverage build adds additional dependencies for the coverage-only runtime libraries.
// Requiring them and their transitive depencies with apex_available is not right
// because they just add noise.
@@ -1782,7 +1817,7 @@
return
}
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if externalDep {
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
@@ -1818,6 +1853,17 @@
}
}
+func (a *apexBundle) checkMinSdkVersion(ctx android.ModuleContext) {
+ if a.testApex || a.vndkApex {
+ return
+ }
+ // Meaningless to check min_sdk_version when building use_vendor modules against non-Trebleized targets
+ if proptools.Bool(a.properties.Use_vendor) && ctx.DeviceConfig().VndkVersion() == "" {
+ return
+ }
+ android.CheckMinSdkVersion(a, ctx, a.minSdkVersion(ctx))
+}
+
// Ensures that a lib providing stub isn't statically linked
func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) {
// Practically, we only care about regular APEXes on the device.
@@ -1825,7 +1871,7 @@
return
}
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if ccm, ok := to.(*cc.Module); ok {
apexName := ctx.ModuleName()
fromName := ctx.OtherModuleName(from)
@@ -1864,7 +1910,7 @@
}
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
+ buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuildApps()
switch a.properties.ApexType {
case imageApex:
if buildFlattenedAsDefault {
@@ -1900,6 +1946,7 @@
a.checkApexAvailability(ctx)
a.checkUpdatable(ctx)
+ a.checkMinSdkVersion(ctx)
a.checkStaticLinkingToStubLibraries(ctx)
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
@@ -1933,7 +1980,7 @@
})
var filesInfo []apexFile
- // TODO(jiyong) do this using walkPayloadDeps
+ // TODO(jiyong) do this using WalkPayloadDeps
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
depTag := ctx.OtherModuleDependencyTag(child)
if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
@@ -2077,7 +2124,7 @@
}
af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
af.transitiveDep = true
- if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), ctx.OtherModuleName(cc)) && (cc.IsStubs() || cc.HasStubsVariants()) {
+ if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
// If the dependency is a stubs lib, don't include it in this APEX,
// but make sure that the lib is installed on the device.
// In case no APEX is having the lib, the lib is installed to the system
@@ -2085,8 +2132,17 @@
//
// Always include if we are a host-apex however since those won't have any
// system libraries.
- if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.BaseModuleName(), a.requiredDeps) {
- a.requiredDeps = append(a.requiredDeps, cc.BaseModuleName())
+ if !android.DirectlyInAnyApex(ctx, depName) {
+ // we need a module name for Make
+ name := cc.BaseModuleName() + cc.Properties.SubName
+ if proptools.Bool(a.properties.Use_vendor) {
+ // we don't use subName(.vendor) for a "use_vendor: true" apex
+ // which is supposed to be installed in /system
+ name = cc.BaseModuleName()
+ }
+ if !android.InList(name, a.requiredDeps) {
+ a.requiredDeps = append(a.requiredDeps, name)
+ }
}
requireNativeLibs = append(requireNativeLibs, af.Stem())
// Don't track further
@@ -2172,22 +2228,6 @@
a.installDir = android.PathForModuleInstall(ctx, "apex")
a.filesInfo = filesInfo
- if a.properties.ApexType != zipApex {
- if a.properties.File_contexts == nil {
- a.fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
- } else {
- a.fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts)
- if a.Platform() {
- if matched, err := path.Match("system/sepolicy/**/*", a.fileContexts.String()); err != nil || !matched {
- ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but %q", a.fileContexts)
- }
- }
- }
- if !android.ExistentPathForSource(ctx, a.fileContexts.String()).Valid() {
- ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", a.fileContexts)
- return
- }
- }
// Optimization. If we are building bundled APEX, for the files that are gathered due to the
// transitive dependencies, don't place them inside the APEX, but place a symlink pointing
// the same library in the system partition, thus effectively sharing the same libraries
@@ -2197,6 +2237,12 @@
a.installable() &&
!proptools.Bool(a.properties.Use_vendor)
+ // APEXes targeting other than system/system_ext partitions use vendor/product variants.
+ // So we can't link them to /system/lib libs which are core variants.
+ if a.SocSpecific() || a.DeviceSpecific() || a.ProductSpecific() {
+ a.linkToSystemLib = false
+ }
+
// We don't need the optimization for updatable APEXes, as it might give false signal
// to the system health when the APEXes are still bundled (b/149805758)
if a.Updatable() && a.properties.ApexType == imageApex {
@@ -2211,6 +2257,8 @@
// prepare apex_manifest.json
a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
+ a.buildFileContexts(ctx)
+
a.setCertificateAndPrivateKey(ctx)
if a.properties.ApexType == flattenedApex {
a.buildFlattenedApex(ctx)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index a7a7765..befb814 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -206,6 +206,7 @@
config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q")
config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
for _, handler := range handlers {
@@ -1104,13 +1105,13 @@
}{
{
name: "should link to the latest",
- minSdkVersion: "current",
+ minSdkVersion: "",
shouldLink: "30",
shouldNotLink: []string{"29"},
},
{
name: "should link to llndk#29",
- minSdkVersion: "29",
+ minSdkVersion: "min_sdk_version: \"29\",",
shouldLink: "29",
shouldNotLink: []string{"30"},
},
@@ -1123,7 +1124,7 @@
key: "myapex.key",
use_vendor: true,
native_shared_libs: ["mylib"],
- min_sdk_version: "`+tc.minSdkVersion+`",
+ `+tc.minSdkVersion+`
}
apex_key {
@@ -1140,6 +1141,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1270,24 +1272,24 @@
ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
}
-func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) {
+func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) {
// there are three links between liba --> libz
- // 1) myapex -> libx -> liba -> libz : this should be #2 link, but fallback to #1
- // 2) otherapex -> liby -> liba -> libz : this should be #3 link
+ // 1) myapex -> libx -> liba -> libz : this should be #29 link, but fallback to #28
+ // 2) otherapex -> liby -> liba -> libz : this should be #30 link
// 3) (platform) -> liba -> libz : this should be non-stub link
ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
native_shared_libs: ["libx"],
- min_sdk_version: "2",
+ min_sdk_version: "29",
}
apex {
name: "otherapex",
key: "myapex.key",
native_shared_libs: ["liby"],
- min_sdk_version: "3",
+ min_sdk_version: "30",
}
apex_key {
@@ -1302,6 +1304,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1310,6 +1313,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "otherapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1321,6 +1325,7 @@
"//apex_available:anyapex",
"//apex_available:platform",
],
+ min_sdk_version: "29",
}
cc_library {
@@ -1328,10 +1333,10 @@
system_shared_libs: [],
stl: "none",
stubs: {
- versions: ["1", "3"],
+ versions: ["28", "30"],
},
}
- `, withUnbundledBuild)
+ `)
expectLink := func(from, from_variant, to, to_variant string) {
ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
@@ -1343,13 +1348,13 @@
}
// platform liba is linked to non-stub version
expectLink("liba", "shared", "libz", "shared")
- // liba in myapex is linked to #1
- expectLink("liba", "shared_myapex", "libz", "shared_1")
- expectNoLink("liba", "shared_myapex", "libz", "shared_3")
+ // liba in myapex is linked to #28
+ expectLink("liba", "shared_myapex", "libz", "shared_28")
+ expectNoLink("liba", "shared_myapex", "libz", "shared_30")
expectNoLink("liba", "shared_myapex", "libz", "shared")
- // liba in otherapex is linked to #3
- expectLink("liba", "shared_otherapex", "libz", "shared_3")
- expectNoLink("liba", "shared_otherapex", "libz", "shared_1")
+ // liba in otherapex is linked to #30
+ expectLink("liba", "shared_otherapex", "libz", "shared_30")
+ expectNoLink("liba", "shared_otherapex", "libz", "shared_28")
expectNoLink("liba", "shared_otherapex", "libz", "shared")
}
@@ -1374,6 +1379,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
+ min_sdk_version: "R",
}
cc_library {
@@ -1407,7 +1413,7 @@
expectNoLink("libx", "shared_myapex", "libz", "shared")
}
-func TestApexMinSdkVersionDefaultsToLatest(t *testing.T) {
+func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) {
ctx, _ := testApex(t, `
apex {
name: "myapex",
@@ -1516,6 +1522,7 @@
name: "libx",
shared_libs: ["libbar"],
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1553,6 +1560,7 @@
cc_library {
name: "libx",
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
`)
@@ -1564,7 +1572,7 @@
ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
}
-func TestInvalidMinSdkVersion(t *testing.T) {
+func TestApexMinSdkVersion_ErrorIfIncompatibleStubs(t *testing.T) {
testApexError(t, `"libz" .*: not found a version\(<=29\)`, `
apex {
name: "myapex",
@@ -1585,6 +1593,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1596,12 +1605,15 @@
},
}
`)
+}
- testApexError(t, `"myapex" .*: min_sdk_version: SDK version should be .*`, `
+func TestApexMinSdkVersion_ErrorIfIncompatibleVersion(t *testing.T) {
+ testApexError(t, `module "mylib".*: should support min_sdk_version\(29\)`, `
apex {
name: "myapex",
key: "myapex.key",
- min_sdk_version: "abc",
+ native_shared_libs: ["mylib"],
+ min_sdk_version: "29",
}
apex_key {
@@ -1609,6 +1621,67 @@
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "30",
+ }
+ `)
+}
+
+func TestApexMinSdkVersion_Okay(t *testing.T) {
+ testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ java_libs: ["libbar"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libfoo_dep"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
+
+ cc_library {
+ name: "libfoo_dep",
+ srcs: ["mylib.cpp"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
+
+ java_library {
+ name: "libbar",
+ sdk_version: "current",
+ srcs: ["a.java"],
+ static_libs: ["libbar_dep"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
+
+ java_library {
+ name: "libbar_dep",
+ sdk_version: "current",
+ srcs: ["a.java"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
`)
}
@@ -1659,6 +1732,7 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "current",
apex_available: ["myapex"],
+ min_sdk_version: "29",
}
`,
},
@@ -1728,6 +1802,135 @@
}
}
+func TestApexMinSdkVersion_ErrorIfDepIsNewer(t *testing.T) {
+ testApexError(t, `module "mylib2".*: should support min_sdk_version\(29\) for "myapex"`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["mylib2"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "29",
+ }
+
+ // indirect part of the apex
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "30",
+ }
+ `)
+}
+
+func TestApexMinSdkVersion_ErrorIfDepIsNewer_Java(t *testing.T) {
+ testApexError(t, `module "bar".*: should support min_sdk_version\(29\) for "myapex"`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ apps: ["AppFoo"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ android_app {
+ name: "AppFoo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "current",
+ min_sdk_version: "29",
+ system_modules: "none",
+ stl: "none",
+ static_libs: ["bar"],
+ apex_available: [ "myapex" ],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["a.java"],
+ apex_available: [ "myapex" ],
+ }
+ `)
+}
+
+func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ // mylib in myapex will link to mylib2#29
+ // mylib in otherapex will link to mylib2(non-stub) in otherapex as well
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["mylib2"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: ["myapex", "otherapex"],
+ min_sdk_version: "29",
+ }
+
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: ["otherapex"],
+ stubs: { versions: ["29", "30"] },
+ min_sdk_version: "30",
+ }
+
+ apex {
+ name: "otherapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib", "mylib2"],
+ min_sdk_version: "30",
+ }
+ `)
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld")
+ libFlags := ld.Args["libFlags"]
+ ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectLink("mylib", "shared_myapex", "mylib2", "shared_29")
+ expectLink("mylib", "shared_otherapex", "mylib2", "shared_otherapex")
+}
+
func TestFilesInSubDir(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -1902,7 +2105,7 @@
ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib2.so")
}
-func TestUseVendorRestriction(t *testing.T) {
+func TestUseVendorNotAllowedForSystemApexes(t *testing.T) {
testApexError(t, `module "myapex" .*: use_vendor: not allowed`, `
apex {
name: "myapex",
@@ -1958,6 +2161,141 @@
`)
}
+func TestVendorApex(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ binaries: ["mybin"],
+ vendor: true,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_binary {
+ name: "mybin",
+ vendor: true,
+ shared_libs: ["libfoo"],
+ }
+ cc_library {
+ name: "libfoo",
+ proprietary: true,
+ }
+ `)
+
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "bin/mybin",
+ "lib64/libfoo.so",
+ // TODO(b/159195575): Add an option to use VNDK libs from VNDK APEX
+ "lib64/libc++.so",
+ })
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, `LOCAL_MODULE_PATH := /tmp/target/product/test_device/vendor/apex`)
+}
+
+func TestAndroidMk_UseVendorRequired(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ use_vendor: true,
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ vendor_available: true,
+ apex_available: ["myapex"],
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ setUseVendorAllowListForTest(config, []string{"myapex"})
+ })
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += libc libm libdl\n")
+}
+
+func TestAndroidMk_VendorApexRequired(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ vendor: true,
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ vendor_available: true,
+ }
+ `)
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += libc.vendor libm.vendor libdl.vendor\n")
+}
+
+func TestAndroidMkWritesCommonProperties(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ vintf_fragments: ["fragment.xml"],
+ init_rc: ["init.rc"],
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_binary {
+ name: "mybin",
+ }
+ `)
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_VINTF_FRAGMENTS := fragment.xml\n")
+ ensureContains(t, androidMk, "LOCAL_INIT_RC := init.rc\n")
+}
+
func TestStaticLinking(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -2217,6 +2555,7 @@
"otherapex",
],
recovery_available: true,
+ min_sdk_version: "29",
}
cc_library {
name: "mylib2",
@@ -2228,6 +2567,7 @@
"otherapex",
],
use_apex_name_macro: true,
+ min_sdk_version: "29",
}
`)
@@ -3275,110 +3615,104 @@
}
}
-func TestFileContexts(t *testing.T) {
+func TestFileContexts_FindInDefaultLocationIfNotSet(t *testing.T) {
ctx, _ := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- }
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
`)
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
- apexRule := module.Rule("apexRule")
- actual := apexRule.Args["file_contexts"]
- expected := "system/sepolicy/apex/myapex-file_contexts"
- if actual != expected {
- t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual)
- }
+ rule := module.Output("file_contexts")
+ ensureContains(t, rule.RuleParams.Command, "cat system/sepolicy/apex/myapex-file_contexts")
+}
+func TestFileContexts_ShouldBeUnderSystemSepolicyForSystemApexes(t *testing.T) {
testApexError(t, `"myapex" .*: file_contexts: should be under system/sepolicy`, `
- apex {
- name: "myapex",
- key: "myapex.key",
- file_contexts: "my_own_file_contexts",
- }
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: "my_own_file_contexts",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
`, withFiles(map[string][]byte{
"my_own_file_contexts": nil,
}))
+}
+func TestFileContexts_ProductSpecificApexes(t *testing.T) {
testApexError(t, `"myapex" .*: file_contexts: cannot find`, `
- apex {
- name: "myapex",
- key: "myapex.key",
- product_specific: true,
- file_contexts: "product_specific_file_contexts",
- }
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ product_specific: true,
+ file_contexts: "product_specific_file_contexts",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
`)
- ctx, _ = testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- product_specific: true,
- file_contexts: "product_specific_file_contexts",
- }
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ product_specific: true,
+ file_contexts: "product_specific_file_contexts",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
`, withFiles(map[string][]byte{
"product_specific_file_contexts": nil,
}))
- module = ctx.ModuleForTests("myapex", "android_common_myapex_image")
- apexRule = module.Rule("apexRule")
- actual = apexRule.Args["file_contexts"]
- expected = "product_specific_file_contexts"
- if actual != expected {
- t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual)
- }
+ module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+ rule := module.Output("file_contexts")
+ ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts")
+}
- ctx, _ = testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- product_specific: true,
- file_contexts: ":my-file-contexts",
- }
+func TestFileContexts_SetViaFileGroup(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ product_specific: true,
+ file_contexts: ":my-file-contexts",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
- filegroup {
- name: "my-file-contexts",
- srcs: ["product_specific_file_contexts"],
- }
+ filegroup {
+ name: "my-file-contexts",
+ srcs: ["product_specific_file_contexts"],
+ }
`, withFiles(map[string][]byte{
"product_specific_file_contexts": nil,
}))
- module = ctx.ModuleForTests("myapex", "android_common_myapex_image")
- apexRule = module.Rule("apexRule")
- actual = apexRule.Args["file_contexts"]
- expected = "product_specific_file_contexts"
- if actual != expected {
- t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual)
- }
+ module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+ rule := module.Output("file_contexts")
+ ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts")
}
func TestApexKeyFromOtherModule(t *testing.T) {
@@ -4349,6 +4683,7 @@
stl: "libc++",
system_shared_libs: [],
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
`, withUnbundledBuild)
@@ -4749,6 +5084,7 @@
"myapex.updatable",
"//apex_available:platform",
],
+ min_sdk_version: "current",
}
cc_library {
@@ -4761,6 +5097,7 @@
"myapex.updatable",
"//apex_available:platform",
],
+ min_sdk_version: "current",
}
java_library {
@@ -4774,6 +5111,7 @@
"myapex.updatable",
"//apex_available:platform",
],
+ min_sdk_version: "current",
}
java_library {
@@ -4786,6 +5124,7 @@
"myapex.updatable",
"//apex_available:platform",
],
+ min_sdk_version: "current",
}
`
@@ -5393,7 +5732,62 @@
apexKeysText := ctx.SingletonForTests("apex_keys_text")
content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
ensureContains(t, content, `name="myapex_set.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
- ensureNotContains(t, content, "myapex.apex")
+ ensureContains(t, content, `name="myapex.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
+}
+
+func TestAllowedFiles(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ apps: ["app"],
+ allowed_files: "allowed.txt",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ android_app {
+ name: "app",
+ srcs: ["foo/bar/MyClass.java"],
+ package_name: "foo",
+ sdk_version: "none",
+ system_modules: "none",
+ apex_available: [ "myapex" ],
+ }
+ `, withFiles(map[string][]byte{
+ "sub/Android.bp": []byte(`
+ override_apex {
+ name: "override_myapex",
+ base: "myapex",
+ apps: ["override_app"],
+ allowed_files: ":allowed",
+ }
+ // Overridable "path" property should be referenced indirectly
+ filegroup {
+ name: "allowed",
+ srcs: ["allowed.txt"],
+ }
+ override_android_app {
+ name: "override_app",
+ base: "app",
+ package_name: "bar",
+ }
+ `),
+ }))
+
+ rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("diffApexContentRule")
+ if expected, actual := "allowed.txt", rule.Args["allowed_files_file"]; expected != actual {
+ t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
+ }
+
+ rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Rule("diffApexContentRule")
+ if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual {
+ t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
+ }
}
func TestMain(m *testing.M) {
diff --git a/apex/builder.go b/apex/builder.go
index 53c1193..ede11d0 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -17,6 +17,7 @@
import (
"encoding/json"
"fmt"
+ "path"
"path/filepath"
"runtime"
"sort"
@@ -231,10 +232,42 @@
})
}
+func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) {
+ if a.properties.ApexType == zipApex {
+ return
+ }
+ var fileContexts android.Path
+ if a.properties.File_contexts == nil {
+ fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
+ } else {
+ fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts)
+ }
+ if a.Platform() {
+ if matched, err := path.Match("system/sepolicy/**/*", fileContexts.String()); err != nil || !matched {
+ ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but %q", fileContexts)
+ return
+ }
+ }
+ if !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() {
+ ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", a.fileContexts)
+ return
+ }
+
+ output := android.PathForModuleOut(ctx, "file_contexts")
+ rule := android.NewRuleBuilder()
+ rule.Command().Text("rm").FlagWithOutput("-f ", output)
+ rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
+ rule.Command().Text("echo").Text(">>").Output(output)
+ rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
+ rule.Build(pctx, ctx, "file_contexts."+a.Name(), "Generate file_contexts")
+
+ a.fileContexts = output.OutputPath
+}
+
func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
var noticeFiles android.Paths
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if externalDep {
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
@@ -391,7 +424,7 @@
emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String())
implicitInputs = append(implicitInputs, a.manifestPbOut)
- if a.properties.Allowed_files != nil {
+ if a.overridableProperties.Allowed_files != nil {
ctx.Build(pctx, android.BuildParams{
Rule: emitApexContentRule,
Implicits: implicitInputs,
@@ -402,7 +435,7 @@
},
})
implicitInputs = append(implicitInputs, imageContentFile)
- allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.Allowed_files))
+ allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.overridableProperties.Allowed_files))
phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output")
ctx.Build(pctx, android.BuildParams{
@@ -733,7 +766,7 @@
}
depInfos := android.DepNameToDepInfoMap{}
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if from.Name() == to.Name() {
// This can happen for cc.reuseObjTag. We are not interested in tracking this.
// As soon as the dependency graph crosses the APEX boundary, don't go further.
diff --git a/apex/key.go b/apex/key.go
index a68f6e1..d2d5786 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -160,12 +160,6 @@
presigned: true,
partition: m.PartitionTag(ctx.DeviceConfig()),
}
-
- for _, om := range m.Overrides() {
- if _, ok := apexKeyMap[om]; ok {
- delete(apexKeyMap, om)
- }
- }
apexKeyMap[m.BaseModuleName()] = entry
}
})
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 05cdfcd..60b6ed5 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -118,6 +118,7 @@
t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
ctx, _ := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
+ config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
})
diff --git a/bpfix/Android.bp b/bpfix/Android.bp
index e291578..b244e3a 100644
--- a/bpfix/Android.bp
+++ b/bpfix/Android.bp
@@ -44,11 +44,9 @@
"bpfix/bpfix.go",
],
testSrcs: [
- "bpfix/bpfix_test.go",
+ "bpfix/bpfix_test.go",
],
deps: [
"blueprint-parser",
],
}
-
-
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index e731750..689cbd1 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -533,7 +533,7 @@
updated = true
} else if trimmedPath := strings.TrimPrefix(path, f.prefix+"/"); trimmedPath != path {
m.Properties = append(m.Properties, &parser.Property{
- Name: "sub_dir",
+ Name: "relative_install_path",
Value: &parser.String{Value: trimmedPath},
})
updated = true
@@ -581,6 +581,8 @@
// 'srcs' --> 'src' conversion
convertToSingleSource(mod, "src")
+ renameProperty(mod, "sub_dir", "relative_install_dir")
+
// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
// 'local_module_path'. Analyze its contents and create the correct sub_dir:,
// filename: and boolean attributes combination
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 64a7b93..8988177 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -742,6 +742,22 @@
}
`,
},
+ {
+ name: "prebuilt_etc sub_dir",
+ in: `
+ prebuilt_etc {
+ name: "foo",
+ src: "bar",
+ sub_dir: "baz",
+ }
+ `,
+ out: `prebuilt_etc {
+ name: "foo",
+ src: "bar",
+ relative_install_dir: "baz",
+ }
+ `,
+ },
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index b3ad610..3f812c2 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -249,7 +249,10 @@
entries.Class = "HEADER_LIBRARIES"
}
- entries.DistFile = library.distFile
+ if library.distFile != nil {
+ entries.DistFiles = android.MakeDefaultDistFiles(library.distFile)
+ }
+
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
library.androidMkWriteExportedFlags(entries)
library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries)
@@ -318,7 +321,7 @@
ctx.subAndroidMk(entries, binary.baseInstaller)
entries.Class = "EXECUTABLES"
- entries.DistFile = binary.distFile
+ entries.DistFiles = binary.distFiles
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String())
if len(binary.symlinks) > 0 {
diff --git a/cc/binary.go b/cc/binary.go
index 251b7f0..565cb8a 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -98,8 +98,8 @@
// Output archive of gcno coverage information
coverageOutputFile android.OptionalPath
- // Location of the file that should be copied to dist dir when requested
- distFile android.OptionalPath
+ // Location of the files that should be copied to dist dir when requested
+ distFiles android.TaggedDistFiles
post_install_cmds []string
}
@@ -367,11 +367,11 @@
binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
} else {
versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
- binary.distFile = android.OptionalPathForPath(versionedOutputFile)
+ binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile)
if binary.stripper.needsStrip(ctx) {
out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
- binary.distFile = android.OptionalPathForPath(out)
+ binary.distFiles = android.MakeDefaultDistFiles(out)
binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
}
diff --git a/cc/cc.go b/cc/cc.go
index ebdb46c..81df094 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2905,6 +2905,54 @@
return true
}
+// b/154667674: refactor this to handle "current" in a consistent way
+func decodeSdkVersionString(ctx android.BaseModuleContext, versionString string) (int, error) {
+ if versionString == "" {
+ return 0, fmt.Errorf("not specified")
+ }
+ if versionString == "current" {
+ if ctx.Config().PlatformSdkCodename() == "REL" {
+ return ctx.Config().PlatformSdkVersionInt(), nil
+ }
+ return android.FutureApiLevel, nil
+ }
+ return android.ApiStrToNum(ctx, versionString)
+}
+
+func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // We ignore libclang_rt.* prebuilt libs since they declare sdk_version: 14(b/121358700)
+ if strings.HasPrefix(ctx.OtherModuleName(c), "libclang_rt") {
+ return nil
+ }
+ // b/154569636: set min_sdk_version correctly for toolchain_libraries
+ if c.ToolchainLibrary() {
+ return nil
+ }
+ // We don't check for prebuilt modules
+ if _, ok := c.linker.(prebuiltLinkerInterface); ok {
+ return nil
+ }
+ minSdkVersion := c.MinSdkVersion()
+ if minSdkVersion == "apex_inherit" {
+ return nil
+ }
+ if minSdkVersion == "" {
+ // JNI libs within APK-in-APEX fall into here
+ // Those are okay to set sdk_version instead
+ // We don't have to check if this is a SDK variant because
+ // non-SDK variant resets sdk_version, which works too.
+ minSdkVersion = c.SdkVersion()
+ }
+ ver, err := decodeSdkVersionString(ctx, minSdkVersion)
+ if err != nil {
+ return err
+ }
+ if ver > sdkVersion {
+ return fmt.Errorf("newer SDK(%v)", ver)
+ }
+ return nil
+}
+
//
// Defaults
//
@@ -2940,6 +2988,7 @@
&BinaryLinkerProperties{},
&TestProperties{},
&TestBinaryProperties{},
+ &BenchmarkProperties{},
&FuzzProperties{},
&StlProperties{},
&SanitizeProperties{},
diff --git a/cc/coverage.go b/cc/coverage.go
index 1a559a9..c823324 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -74,8 +74,8 @@
}
func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
- gcovCoverage := ctx.DeviceConfig().NativeCoverageEnabled()
clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled()
+ gcovCoverage := ctx.DeviceConfig().GcovCoverageEnabled()
if !gcovCoverage && !clangCoverage {
return flags, deps
@@ -161,7 +161,7 @@
func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool,
useSdk bool, sdkVersion string) CoverageProperties {
// Coverage is disabled globally
- if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
+ if !ctx.DeviceConfig().NativeCoverageEnabled() {
return properties
}
diff --git a/cc/library.go b/cc/library.go
index 968702e..98f4d48 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -369,7 +369,7 @@
unstrippedOutputFile android.Path
// Location of the file that should be copied to dist dir when requested
- distFile android.OptionalPath
+ distFile android.Path
versionScriptPath android.ModuleGenPath
@@ -894,7 +894,7 @@
library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
} else {
versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
- library.distFile = android.OptionalPathForPath(versionedOutputFile)
+ library.distFile = versionedOutputFile
library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
}
}
@@ -988,11 +988,11 @@
library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
} else {
versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
- library.distFile = android.OptionalPathForPath(versionedOutputFile)
+ library.distFile = versionedOutputFile
if library.stripper.needsStrip(ctx) {
out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
- library.distFile = android.OptionalPathForPath(out)
+ library.distFile = out
library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 4410302..9c54399 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -380,7 +380,11 @@
// Make sure that the include directories are unique.
p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs)
p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs)
- p.ExportedSystemIncludeDirs = android.FirstUniquePaths(ccModule.ExportedSystemIncludeDirs())
+
+ // Take a copy before filtering out duplicates to avoid changing the slice owned by the
+ // ccModule.
+ dirs := append(android.Paths(nil), ccModule.ExportedSystemIncludeDirs()...)
+ p.ExportedSystemIncludeDirs = android.FirstUniquePaths(dirs)
p.ExportedFlags = ccModule.ExportedFlags()
if ccModule.linker != nil {
diff --git a/cc/linker.go b/cc/linker.go
index c9cbd9b..58f8a29 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -298,17 +298,6 @@
}
}
- if inList("libc_scudo", deps.SharedLibs) {
- // libc_scudo is an alternate implementation of all
- // allocation functions (malloc, free), that uses
- // the scudo allocator instead of the default native
- // allocator. If this library is in the list, make
- // sure it's first so it properly overrides the
- // allocation functions of all other shared libraries.
- _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
- deps.SharedLibs = append([]string{"libc_scudo"}, deps.SharedLibs...)
- }
-
// If libc and libdl are both in system_shared_libs make sure libdl comes after libc
// to avoid loading libdl before libc.
if inList("libdl", systemSharedLibs) && inList("libc", systemSharedLibs) &&
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index c4d7708..acdc581 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -145,6 +145,7 @@
libraryDecorator: library,
}
module.installer = nil
+ module.Properties.Sdk_version = StringPtr("minimum")
module.Properties.HideFromMake = true
module.Properties.AlwaysSdk = true
module.Properties.Sdk_version = StringPtr("current")
diff --git a/cc/pgo.go b/cc/pgo.go
index 88903bb..9298e7a 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -34,7 +34,7 @@
globalPgoProfileProjects = []string{
"toolchain/pgo-profiles",
- "vendor/google_data/pgo-profiles",
+ "vendor/google_data/pgo_profile",
}
)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index aaaf694..72ad6d7 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -408,16 +408,6 @@
return deps
}
- if ctx.Device() {
- if Bool(sanitize.Properties.Sanitize.Address) {
- // Compiling asan and having libc_scudo in the same
- // executable will cause the executable to crash.
- // Remove libc_scudo since it is only used to override
- // allocation functions which asan already overrides.
- _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
- }
- }
-
return deps
}
diff --git a/cc/testing.go b/cc/testing.go
index 479b424..b5cf45c 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -273,6 +273,7 @@
vendor_available: true,
recovery_available: true,
host_supported: true,
+ min_sdk_version: "29",
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
@@ -287,6 +288,7 @@
vendor_available: true,
recovery_available: true,
host_supported: true,
+ min_sdk_version: "29",
vndk: {
enabled: true,
support_system_process: true,
@@ -305,6 +307,7 @@
host_supported: false,
vendor_available: true,
recovery_available: true,
+ min_sdk_version: "29",
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
@@ -338,6 +341,7 @@
recovery_available: true,
vendor_available: true,
native_bridge_supported: true,
+ min_sdk_version: "29",
stl: "none",
}
@@ -365,6 +369,7 @@
recovery_available: true,
vendor_available: true,
native_bridge_supported: true,
+ min_sdk_version: "29",
stl: "none",
}
diff --git a/cmd/extract_apks/Android.bp b/cmd/extract_apks/Android.bp
index 90548cd..f8fe864 100644
--- a/cmd/extract_apks/Android.bp
+++ b/cmd/extract_apks/Android.bp
@@ -6,7 +6,7 @@
"golang-protobuf-proto",
"soong-cmd-extract_apks-proto",
],
- testSrcs: ["main_test.go"]
+ testSrcs: ["main_test.go"],
}
bootstrap_go_package {
diff --git a/cmd/extract_jar_packages/Android.bp b/cmd/extract_jar_packages/Android.bp
index ea0cbbf..4ea8798 100644
--- a/cmd/extract_jar_packages/Android.bp
+++ b/cmd/extract_jar_packages/Android.bp
@@ -22,4 +22,3 @@
"extract_jar_packages.go",
],
}
-
diff --git a/cmd/extract_linker/Android.bp b/cmd/extract_linker/Android.bp
index fe76ae4..690c4fa 100644
--- a/cmd/extract_linker/Android.bp
+++ b/cmd/extract_linker/Android.bp
@@ -17,4 +17,3 @@
srcs: ["main.go"],
testSrcs: ["main_test.go"],
}
-
diff --git a/cmd/merge_zips/Android.bp b/cmd/merge_zips/Android.bp
index f70c86e..8c97b6d 100644
--- a/cmd/merge_zips/Android.bp
+++ b/cmd/merge_zips/Android.bp
@@ -15,10 +15,10 @@
blueprint_go_binary {
name: "merge_zips",
deps: [
- "android-archive-zip",
- "blueprint-pathtools",
- "soong-jar",
- "soong-zip",
+ "android-archive-zip",
+ "blueprint-pathtools",
+ "soong-jar",
+ "soong-zip",
],
srcs: [
"merge_zips.go",
@@ -27,4 +27,3 @@
"merge_zips_test.go",
],
}
-
diff --git a/cmd/sbox/Android.bp b/cmd/sbox/Android.bp
index a706810d..6fa304e 100644
--- a/cmd/sbox/Android.bp
+++ b/cmd/sbox/Android.bp
@@ -19,4 +19,3 @@
"sbox.go",
],
}
-
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 6b79823..b559bac 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -29,4 +29,3 @@
],
primaryBuilder: true,
}
-
diff --git a/cmd/soong_env/Android.bp b/cmd/soong_env/Android.bp
index 4cdc396..4db0da3 100644
--- a/cmd/soong_env/Android.bp
+++ b/cmd/soong_env/Android.bp
@@ -22,4 +22,3 @@
],
default: true,
}
-
diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp
index 68d8bc7..2c4cd82 100644
--- a/cmd/zip2zip/Android.bp
+++ b/cmd/zip2zip/Android.bp
@@ -24,4 +24,3 @@
],
testSrcs: ["zip2zip_test.go"],
}
-
diff --git a/cmd/zipsync/Android.bp b/cmd/zipsync/Android.bp
index 22feadc..49b5f3e 100644
--- a/cmd/zipsync/Android.bp
+++ b/cmd/zipsync/Android.bp
@@ -22,4 +22,3 @@
"zipsync.go",
],
}
-
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index bc44b21..4a4e834 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -383,7 +383,7 @@
SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"),
Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"),
ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"),
- ConstructContext: android.PathForSource(ctx, "build/make/core/construct_context.sh"),
+ ConstructContext: android.PathForSource(ctx, "build/soong/scripts/construct_context.sh"),
}
}
diff --git a/dexpreopt/dexpreopt_gen/Android.bp b/dexpreopt/dexpreopt_gen/Android.bp
index 0790391..3f0619c 100644
--- a/dexpreopt/dexpreopt_gen/Android.bp
+++ b/dexpreopt/dexpreopt_gen/Android.bp
@@ -8,4 +8,4 @@
"blueprint-pathtools",
"blueprint-proptools",
],
-}
\ No newline at end of file
+}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index df6d79d..0f7b8df 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -42,9 +42,12 @@
// Source file of this prebuilt.
Src *string `android:"path,arch_variant"`
- // optional subdirectory under which this file is installed into
+ // optional subdirectory under which this file is installed into, cannot be specified with relative_install_path, prefer relative_install_path
Sub_dir *string `android:"arch_variant"`
+ // optional subdirectory under which this file is installed into, cannot be specified with sub_dir
+ Relative_install_path *string `android:"arch_variant"`
+
// optional name for the installed file. If unspecified, name of the module is used as the file name
Filename *string `android:"arch_variant"`
@@ -158,7 +161,10 @@
}
func (p *PrebuiltEtc) SubDir() string {
- return android.String(p.properties.Sub_dir)
+ if subDir := proptools.String(p.properties.Sub_dir); subDir != "" {
+ return subDir
+ }
+ return proptools.String(p.properties.Relative_install_path)
}
func (p *PrebuiltEtc) Installable() bool {
@@ -181,13 +187,17 @@
}
p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
+ if p.properties.Sub_dir != nil && p.properties.Relative_install_path != nil {
+ ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
+ }
+
// If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
// socInstallDirBase.
installBaseDir := p.installDirBase
if ctx.SocSpecific() && p.socInstallDirBase != "" {
installBaseDir = p.socInstallDirBase
}
- p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, proptools.String(p.properties.Sub_dir))
+ p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
// This ensures that outputFilePath has the correct name for others to
// use, as the source file may have a different name.
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 4ce1984..8fc36c2 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -49,7 +49,7 @@
os.Exit(run())
}
-func testPrebuiltEtc(t *testing.T, bp string) (*android.TestContext, android.Config) {
+func testPrebuiltEtcContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
fs := map[string][]byte{
"foo.conf": nil,
"bar.conf": nil,
@@ -67,6 +67,14 @@
ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
ctx.Register(config)
+
+ return ctx, config
+}
+
+func testPrebuiltEtc(t *testing.T, bp string) (*android.TestContext, android.Config) {
+ t.Helper()
+
+ ctx, config := testPrebuiltEtcContext(t, bp)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
@@ -75,6 +83,24 @@
return ctx, config
}
+func testPrebuiltEtcError(t *testing.T, pattern, bp string) {
+ t.Helper()
+
+ ctx, config := testPrebuiltEtcContext(t, bp)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ _, errs = ctx.PrepareBuildActions(config)
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
func TestPrebuiltEtcVariants(t *testing.T) {
ctx, _ := testPrebuiltEtc(t, `
prebuilt_etc {
@@ -184,6 +210,33 @@
}
}
+func TestPrebuiltEtcRelativeInstallPathInstallDirPath(t *testing.T) {
+ ctx, _ := testPrebuiltEtc(t, `
+ prebuilt_etc {
+ name: "foo.conf",
+ src: "foo.conf",
+ relative_install_path: "bar",
+ }
+ `)
+
+ p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc)
+ expected := buildDir + "/target/product/test_device/system/etc/bar"
+ if p.installDirPath.String() != expected {
+ t.Errorf("expected %q, got %q", expected, p.installDirPath.String())
+ }
+}
+
+func TestPrebuiltEtcCannotSetRelativeInstallPathAndSubDir(t *testing.T) {
+ testPrebuiltEtcError(t, "relative_install_path is set. Cannot set sub_dir", `
+ prebuilt_etc {
+ name: "foo.conf",
+ src: "foo.conf",
+ sub_dir: "bar",
+ relative_install_path: "bar",
+ }
+ `)
+}
+
func TestPrebuiltEtcHost(t *testing.T) {
ctx, _ := testPrebuiltEtc(t, `
prebuilt_etc_host {
diff --git a/finder/Android.bp b/finder/Android.bp
index 47b47c9..a5d7fd4 100644
--- a/finder/Android.bp
+++ b/finder/Android.bp
@@ -17,7 +17,7 @@
//
subdirs = [
- "cmd"
+ "cmd",
]
bootstrap_go_package {
@@ -30,8 +30,6 @@
"finder_test.go",
],
deps: [
- "soong-finder-fs",
+ "soong-finder-fs",
],
}
-
-
diff --git a/finder/cmd/Android.bp b/finder/cmd/Android.bp
index 9dc84ae..e066c39 100644
--- a/finder/cmd/Android.bp
+++ b/finder/cmd/Android.bp
@@ -22,8 +22,6 @@
"finder.go",
],
deps: [
- "soong-finder"
+ "soong-finder",
],
}
-
-
diff --git a/finder/finder.go b/finder/finder.go
index 89be0f5..f20bed2 100644
--- a/finder/finder.go
+++ b/finder/finder.go
@@ -1393,17 +1393,25 @@
for _, child := range children {
linkBits := child.Mode() & os.ModeSymlink
isLink := linkBits != 0
- if child.IsDir() {
- if !isLink {
+ if isLink {
+ childPath := filepath.Join(path, child.Name())
+ childStat, err := f.filesystem.Stat(childPath)
+ if err != nil {
+ // If stat fails this is probably a broken or dangling symlink, treat it as a file.
+ subfiles = append(subfiles, child.Name())
+ } else if childStat.IsDir() {
// Skip symlink dirs.
// We don't have to support symlink dirs because
// that would cause duplicates.
- subdirs = append(subdirs, child.Name())
+ } else {
+ // We do have to support symlink files because the link name might be
+ // different than the target name
+ // (for example, Android.bp -> build/soong/root.bp)
+ subfiles = append(subfiles, child.Name())
}
+ } else if child.IsDir() {
+ subdirs = append(subdirs, child.Name())
} else {
- // We do have to support symlink files because the link name might be
- // different than the target name
- // (for example, Android.bp -> build/soong/root.bp)
subfiles = append(subfiles, child.Name())
}
diff --git a/finder/finder_test.go b/finder/finder_test.go
index f6d0aa9..88b0c05 100644
--- a/finder/finder_test.go
+++ b/finder/finder_test.go
@@ -20,11 +20,8 @@
"log"
"os"
"path/filepath"
- "reflect"
- "runtime/debug"
"sort"
"testing"
- "time"
"android/soong/finder/fs"
)
@@ -41,7 +38,7 @@
func newFinderWithNumThreads(t *testing.T, filesystem *fs.MockFs, cacheParams CacheParams, numThreads int) *Finder {
f, err := newFinderAndErr(t, filesystem, cacheParams, numThreads)
if err != nil {
- fatal(t, err.Error())
+ t.Fatal(err.Error())
}
return f
}
@@ -62,7 +59,7 @@
func finderWithSameParams(t *testing.T, original *Finder) *Finder {
f, err := finderAndErrorWithSameParams(t, original)
if err != nil {
- fatal(t, err.Error())
+ t.Fatal(err.Error())
}
return f
}
@@ -78,146 +75,13 @@
return f, err
}
-func write(t *testing.T, path string, content string, filesystem *fs.MockFs) {
- parent := filepath.Dir(path)
- filesystem.MkDirs(parent)
- err := filesystem.WriteFile(path, []byte(content), 0777)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func create(t *testing.T, path string, filesystem *fs.MockFs) {
- write(t, path, "hi", filesystem)
-}
-
-func delete(t *testing.T, path string, filesystem *fs.MockFs) {
- err := filesystem.Remove(path)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func removeAll(t *testing.T, path string, filesystem *fs.MockFs) {
- err := filesystem.RemoveAll(path)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func move(t *testing.T, oldPath string, newPath string, filesystem *fs.MockFs) {
- err := filesystem.Rename(oldPath, newPath)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func link(t *testing.T, newPath string, oldPath string, filesystem *fs.MockFs) {
- parentPath := filepath.Dir(newPath)
- err := filesystem.MkDirs(parentPath)
- if err != nil {
- t.Fatal(err.Error())
- }
- err = filesystem.Symlink(oldPath, newPath)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-func read(t *testing.T, path string, filesystem *fs.MockFs) string {
- reader, err := filesystem.Open(path)
- if err != nil {
- t.Fatalf(err.Error())
- }
- bytes, err := ioutil.ReadAll(reader)
- if err != nil {
- t.Fatal(err.Error())
- }
- return string(bytes)
-}
-func modTime(t *testing.T, path string, filesystem *fs.MockFs) time.Time {
- stats, err := filesystem.Lstat(path)
- if err != nil {
- t.Fatal(err.Error())
- }
- return stats.ModTime()
-}
-func setReadable(t *testing.T, path string, readable bool, filesystem *fs.MockFs) {
- err := filesystem.SetReadable(path, readable)
- if err != nil {
- t.Fatal(err.Error())
- }
-}
-
-func setReadErr(t *testing.T, path string, readErr error, filesystem *fs.MockFs) {
- err := filesystem.SetReadErr(path, readErr)
- if err != nil {
- t.Fatal(err.Error())
- }
-}
-
-func fatal(t *testing.T, message string) {
- t.Error(message)
- debug.PrintStack()
- t.FailNow()
-}
-
-func assertSameResponse(t *testing.T, actual []string, expected []string) {
- sort.Strings(actual)
- sort.Strings(expected)
- if !reflect.DeepEqual(actual, expected) {
- fatal(
- t,
- fmt.Sprintf(
- "Expected Finder to return these %v paths:\n %v,\ninstead returned these %v paths: %v\n",
- len(expected), expected, len(actual), actual),
- )
- }
-}
-
-func assertSameStatCalls(t *testing.T, actual []string, expected []string) {
- sort.Strings(actual)
- sort.Strings(expected)
-
- if !reflect.DeepEqual(actual, expected) {
- fatal(
- t,
- fmt.Sprintf(
- "Finder made incorrect Stat calls.\n"+
- "Actual:\n"+
- "%v\n"+
- "Expected:\n"+
- "%v\n"+
- "\n",
- actual, expected),
- )
- }
-}
-func assertSameReadDirCalls(t *testing.T, actual []string, expected []string) {
- sort.Strings(actual)
- sort.Strings(expected)
-
- if !reflect.DeepEqual(actual, expected) {
- fatal(
- t,
- fmt.Sprintf(
- "Finder made incorrect ReadDir calls.\n"+
- "Actual:\n"+
- "%v\n"+
- "Expected:\n"+
- "%v\n"+
- "\n",
- actual, expected),
- )
- }
-}
-
// runSimpleTests creates a few files, searches for findme.txt, and checks for the expected matches
func runSimpleTest(t *testing.T, existentPaths []string, expectedMatches []string) {
filesystem := newFs()
root := "/tmp"
filesystem.MkDirs(root)
for _, path := range existentPaths {
- create(t, filepath.Join(root, path), filesystem)
+ fs.Create(t, filepath.Join(root, path), filesystem)
}
finder := newFinder(t,
@@ -237,7 +101,7 @@
for i := range expectedMatches {
absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i]))
}
- assertSameResponse(t, foundPaths, absoluteMatches)
+ fs.AssertSameResponse(t, foundPaths, absoluteMatches)
}
// testAgainstSeveralThreadcounts runs the given test for each threadcount that we care to test
@@ -288,7 +152,7 @@
func TestEmptyPath(t *testing.T) {
filesystem := newFs()
root := "/tmp"
- create(t, filepath.Join(root, "findme.txt"), filesystem)
+ fs.Create(t, filepath.Join(root, "findme.txt"), filesystem)
finder := newFinder(
t,
@@ -302,7 +166,7 @@
foundPaths := finder.FindNamedAt("", "findme.txt")
- assertSameResponse(t, foundPaths, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{})
}
func TestFilesystemRoot(t *testing.T) {
@@ -311,7 +175,7 @@
filesystem := newFs()
root := "/"
createdPath := "/findme.txt"
- create(t, createdPath, filesystem)
+ fs.Create(t, createdPath, filesystem)
finder := newFinderWithNumThreads(
t,
@@ -326,7 +190,7 @@
foundPaths := finder.FindNamedAt(root, "findme.txt")
- assertSameResponse(t, foundPaths, []string{createdPath})
+ fs.AssertSameResponse(t, foundPaths, []string{createdPath})
}
testAgainstSeveralThreadcounts(t, testWithNumThreads)
@@ -334,7 +198,7 @@
func TestNonexistentDir(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
_, err := newFinderAndErr(
t,
@@ -346,18 +210,18 @@
1,
)
if err == nil {
- fatal(t, "Did not fail when given a nonexistent root directory")
+ t.Fatal("Did not fail when given a nonexistent root directory")
}
}
func TestExcludeDirs(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/exclude/findme.txt", filesystem)
- create(t, "/tmp/exclude/subdir/findme.txt", filesystem)
- create(t, "/tmp/subdir/exclude/findme.txt", filesystem)
- create(t, "/tmp/subdir/subdir/findme.txt", filesystem)
- create(t, "/tmp/subdir/findme.txt", filesystem)
- create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/exclude/findme.txt", filesystem)
+ fs.Create(t, "/tmp/exclude/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/subdir/exclude/findme.txt", filesystem)
+ fs.Create(t, "/tmp/subdir/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
finder := newFinder(
t,
@@ -372,7 +236,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/subdir/findme.txt",
"/tmp/subdir/subdir/findme.txt"})
@@ -380,15 +244,15 @@
func TestPruneFiles(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/out/findme.txt", filesystem)
- create(t, "/tmp/out/.ignore-out-dir", filesystem)
- create(t, "/tmp/out/child/findme.txt", filesystem)
+ fs.Create(t, "/tmp/out/findme.txt", filesystem)
+ fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
+ fs.Create(t, "/tmp/out/child/findme.txt", filesystem)
- create(t, "/tmp/out2/.ignore-out-dir", filesystem)
- create(t, "/tmp/out2/sub/findme.txt", filesystem)
+ fs.Create(t, "/tmp/out2/.ignore-out-dir", filesystem)
+ fs.Create(t, "/tmp/out2/sub/findme.txt", filesystem)
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/include/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/include/findme.txt", filesystem)
finder := newFinder(
t,
@@ -403,7 +267,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/include/findme.txt"})
}
@@ -412,10 +276,10 @@
// tests of the filesystem root are in TestFilesystemRoot
func TestRootDir(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/subdir/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
- create(t, "/tmp/b/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
finder := newFinder(
t,
@@ -429,17 +293,17 @@
foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt",
"/tmp/a/subdir/findme.txt"})
}
func TestUncachedDir(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/subdir/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
- create(t, "/tmp/b/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
finder := newFinder(
t,
@@ -456,7 +320,7 @@
// fail to notice its slowness. Instead, we only ever search the cache for files
// to return, which enforces that we can determine which files will be
// interesting upfront.
- assertSameResponse(t, foundPaths, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{})
finder.Shutdown()
}
@@ -464,9 +328,9 @@
func TestSearchingForFilesExcludedFromCache(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/misc.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/misc.txt", filesystem)
// set up the finder and run it
finder := newFinder(
@@ -483,7 +347,7 @@
// fail to notice its slowness. Instead, we only ever search the cache for files
// to return, which enforces that we can determine which files will be
// interesting upfront.
- assertSameResponse(t, foundPaths, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{})
finder.Shutdown()
}
@@ -491,12 +355,12 @@
func TestRelativeFilePaths(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/ignore/hi.txt", filesystem)
- create(t, "/tmp/include/hi.txt", filesystem)
- create(t, "/cwd/hi.txt", filesystem)
- create(t, "/cwd/a/hi.txt", filesystem)
- create(t, "/cwd/a/a/hi.txt", filesystem)
- create(t, "/rel/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/ignore/hi.txt", filesystem)
+ fs.Create(t, "/tmp/include/hi.txt", filesystem)
+ fs.Create(t, "/cwd/hi.txt", filesystem)
+ fs.Create(t, "/cwd/a/hi.txt", filesystem)
+ fs.Create(t, "/cwd/a/a/hi.txt", filesystem)
+ fs.Create(t, "/rel/a/hi.txt", filesystem)
finder := newFinder(
t,
@@ -509,25 +373,25 @@
defer finder.Shutdown()
foundPaths := finder.FindNamedAt("a", "hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"a/hi.txt",
"a/a/hi.txt"})
foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
foundPaths = finder.FindNamedAt(".", "hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"hi.txt",
"a/hi.txt",
"a/a/hi.txt"})
foundPaths = finder.FindNamedAt("/rel", "hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/rel/a/hi.txt"})
foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
}
// have to run this test with the race-detector (`go test -race src/android/soong/finder/*.go`)
@@ -535,7 +399,7 @@
func TestRootDirsContainedInOtherRootDirs(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt", filesystem)
finder := newFinder(
t,
@@ -549,15 +413,15 @@
foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt"})
}
func TestFindFirst(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/b/hi.txt", filesystem)
- create(t, "/tmp/b/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/a/hi.txt", filesystem)
finder := newFinder(
t,
@@ -571,7 +435,7 @@
foundPaths := finder.FindFirstNamed("hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/hi.txt",
"/tmp/b/hi.txt"},
)
@@ -593,7 +457,7 @@
}
sort.Strings(paths)
for _, path := range paths {
- create(t, path, filesystem)
+ fs.Create(t, path, filesystem)
}
// set up a finder
@@ -621,7 +485,7 @@
// check that each response was correct
for i := 0; i < numTests; i++ {
foundPaths := <-results
- assertSameResponse(t, foundPaths, paths)
+ fs.AssertSameResponse(t, foundPaths, paths)
}
}
@@ -649,7 +513,7 @@
}
sort.Strings(allFiles)
for _, path := range allFiles {
- create(t, path, filesystem)
+ fs.Create(t, path, filesystem)
}
// set up a finder
@@ -687,16 +551,16 @@
// check that each response was correct
for i := 0; i < numTests; i++ {
testRun := <-testRuns
- assertSameResponse(t, testRun.foundMatches, testRun.correctMatches)
+ fs.AssertSameResponse(t, testRun.foundMatches, testRun.correctMatches)
}
}
func TestStrangelyFormattedPaths(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
finder := newFinder(
t,
@@ -710,7 +574,7 @@
foundPaths := finder.FindNamedAt("//tmp//a//..", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt",
"/tmp/b/findme.txt",
"/tmp/findme.txt"})
@@ -719,9 +583,9 @@
func TestCorruptedCacheHeader(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- write(t, "/finder/finder-db", "sample header", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Write(t, "/finder/finder-db", "sample header", filesystem)
finder := newFinder(
t,
@@ -735,7 +599,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt",
"/tmp/findme.txt"})
}
@@ -743,8 +607,8 @@
func TestCanUseCache(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -759,11 +623,11 @@
// check the response of the first finder
correctResponse := []string{"/tmp/a/findme.txt",
"/tmp/findme.txt"}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
finder.Shutdown()
// check results
- cacheText := read(t, finder.DbPath, filesystem)
+ cacheText := fs.Read(t, finder.DbPath, filesystem)
if len(cacheText) < 1 {
t.Fatalf("saved cache db is empty\n")
}
@@ -780,8 +644,8 @@
finder2 := finderWithSameParams(t, finder)
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
- assertSameReadDirCalls(t, filesystem.StatCalls, statCalls)
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameReadDirCalls(t, filesystem.StatCalls, statCalls)
finder2.Shutdown()
}
@@ -789,8 +653,8 @@
func TestCorruptedCacheBody(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -807,7 +671,7 @@
// check the response of the first finder
correctResponse := []string{"/tmp/a/findme.txt",
"/tmp/findme.txt"}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
numStatCalls := len(filesystem.StatCalls)
numReadDirCalls := len(filesystem.ReadDirCalls)
@@ -828,7 +692,7 @@
finder2 := finderWithSameParams(t, finder)
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
numNewStatCalls := len(filesystem.StatCalls)
numNewReadDirCalls := len(filesystem.ReadDirCalls)
// It's permissable to make more Stat calls with a corrupted cache because
@@ -853,7 +717,7 @@
func TestStatCalls(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
// run finder
finder := newFinder(
@@ -868,19 +732,19 @@
finder.Shutdown()
// check response
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
}
func TestFileAdded(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/ignoreme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/ignore.txt", filesystem)
- create(t, "/tmp/b/c/nope.txt", filesystem)
- create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
+ fs.Create(t, "/tmp/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/ignore.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -895,11 +759,11 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/b/c/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/findme.txt", filesystem)
filesystem.Clock.Tick()
filesystem.ClearMetrics()
@@ -908,9 +772,9 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
finder2.Shutdown()
}
@@ -918,11 +782,11 @@
func TestDirectoriesAdded(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/ignoreme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/ignore.txt", filesystem)
- create(t, "/tmp/b/c/nope.txt", filesystem)
- create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
+ fs.Create(t, "/tmp/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/ignore.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -936,13 +800,13 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/b/c/new/findme.txt", filesystem)
- create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
- create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/new/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -950,11 +814,11 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt", "/tmp/b/c/new/findme.txt", "/tmp/b/c/new/new2/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
finder2.Shutdown()
}
@@ -962,8 +826,8 @@
func TestDirectoryAndSubdirectoryBothUpdated(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/hi1.txt", filesystem)
- create(t, "/tmp/a/hi1.txt", filesystem)
+ fs.Create(t, "/tmp/hi1.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi1.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -977,12 +841,12 @@
foundPaths := finder.FindNamedAt("/tmp", "hi1.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/hi2.txt", filesystem)
- create(t, "/tmp/a/hi2.txt", filesystem)
+ fs.Create(t, "/tmp/hi2.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi2.txt", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -990,11 +854,11 @@
foundPaths = finder2.FindAll()
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/hi1.txt", "/tmp/hi2.txt", "/tmp/a/hi1.txt", "/tmp/a/hi2.txt"})
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
finder2.Shutdown()
}
@@ -1002,11 +866,11 @@
func TestFileDeleted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/ignoreme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
- create(t, "/tmp/b/c/nope.txt", filesystem)
- create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
+ fs.Create(t, "/tmp/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1020,11 +884,11 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- delete(t, "/tmp/b/findme.txt", filesystem)
+ fs.Delete(t, "/tmp/b/findme.txt", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1032,9 +896,9 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
finder2.Shutdown()
}
@@ -1042,11 +906,11 @@
func TestDirectoriesDeleted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/1/findme.txt", filesystem)
- create(t, "/tmp/a/1/2/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1060,7 +924,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/a/1/findme.txt",
@@ -1069,7 +933,7 @@
// modify the filesystem
filesystem.Clock.Tick()
- removeAll(t, "/tmp/a/1", filesystem)
+ fs.RemoveAll(t, "/tmp/a/1", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1077,7 +941,7 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/b/findme.txt"})
// Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
// if the Finder detects the nonexistence of /tmp/a/1
@@ -1087,9 +951,9 @@
// The Finder is currently implemented to always restat every dir and
// to not short-circuit due to nonexistence of parents (but it will remove
// missing dirs from the cache for next time)
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
finder2.Shutdown()
}
@@ -1097,11 +961,11 @@
func TestDirectoriesMoved(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/1/findme.txt", filesystem)
- create(t, "/tmp/a/1/2/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1115,7 +979,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/a/1/findme.txt",
@@ -1124,7 +988,7 @@
// modify the filesystem
filesystem.Clock.Tick()
- move(t, "/tmp/a", "/tmp/c", filesystem)
+ fs.Move(t, "/tmp/a", "/tmp/c", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1132,7 +996,7 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/b/findme.txt",
"/tmp/c/findme.txt",
@@ -1146,20 +1010,20 @@
// The Finder is currently implemented to always restat every dir and
// to not short-circuit due to nonexistence of parents (but it will remove
// missing dirs from the cache for next time)
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
finder2.Shutdown()
}
func TestDirectoriesSwapped(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/1/findme.txt", filesystem)
- create(t, "/tmp/a/1/2/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1173,7 +1037,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/a/1/findme.txt",
@@ -1182,9 +1046,9 @@
// modify the filesystem
filesystem.Clock.Tick()
- move(t, "/tmp/a", "/tmp/temp", filesystem)
- move(t, "/tmp/b", "/tmp/a", filesystem)
- move(t, "/tmp/temp", "/tmp/b", filesystem)
+ fs.Move(t, "/tmp/a", "/tmp/temp", filesystem)
+ fs.Move(t, "/tmp/b", "/tmp/a", filesystem)
+ fs.Move(t, "/tmp/temp", "/tmp/b", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1192,7 +1056,7 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/b/findme.txt",
@@ -1206,9 +1070,9 @@
// The Finder is currently implemented to always restat every dir and
// to not short-circuit due to nonexistence of parents (but it will remove
// missing dirs from the cache for next time)
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
finder2.Shutdown()
}
@@ -1217,15 +1081,15 @@
// runFsReplacementTest is a helper method called by other tests
func runFsReplacementTest(t *testing.T, fs1 *fs.MockFs, fs2 *fs.MockFs) {
// setup fs1
- create(t, "/tmp/findme.txt", fs1)
- create(t, "/tmp/a/findme.txt", fs1)
- create(t, "/tmp/a/a/findme.txt", fs1)
+ fs.Create(t, "/tmp/findme.txt", fs1)
+ fs.Create(t, "/tmp/a/findme.txt", fs1)
+ fs.Create(t, "/tmp/a/a/findme.txt", fs1)
// setup fs2 to have the same directories but different files
- create(t, "/tmp/findme.txt", fs2)
- create(t, "/tmp/a/findme.txt", fs2)
- create(t, "/tmp/a/a/ignoreme.txt", fs2)
- create(t, "/tmp/a/b/findme.txt", fs2)
+ fs.Create(t, "/tmp/findme.txt", fs2)
+ fs.Create(t, "/tmp/a/findme.txt", fs2)
+ fs.Create(t, "/tmp/a/a/ignoreme.txt", fs2)
+ fs.Create(t, "/tmp/a/b/findme.txt", fs2)
// run the first finder
finder := newFinder(
@@ -1239,12 +1103,12 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/a/findme.txt"})
// copy the cache data from the first filesystem to the second
- cacheContent := read(t, finder.DbPath, fs1)
- write(t, finder.DbPath, cacheContent, fs2)
+ cacheContent := fs.Read(t, finder.DbPath, fs1)
+ fs.Write(t, finder.DbPath, cacheContent, fs2)
// run the second finder, with the same config and same cache contents but a different filesystem
finder2 := newFinder(
@@ -1258,11 +1122,11 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/b/findme.txt"})
- assertSameStatCalls(t, fs2.StatCalls,
+ fs.AssertSameStatCalls(t, fs2.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
- assertSameReadDirCalls(t, fs2.ReadDirCalls,
+ fs.AssertSameReadDirCalls(t, fs2.ReadDirCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
finder2.Shutdown()
}
@@ -1292,7 +1156,7 @@
// setup filesystem
filesystem := newFs()
for i := 0; i < 5; i++ {
- create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
+ fs.Create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
}
// run the first finder
@@ -1308,7 +1172,7 @@
finder.Shutdown()
// read db file
- string1 := read(t, finder.DbPath, filesystem)
+ string1 := fs.Read(t, finder.DbPath, filesystem)
err := filesystem.Remove(finder.DbPath)
if err != nil {
@@ -1320,7 +1184,7 @@
finder2.FindNamedAt("/tmp", "findme.txt")
finder2.Shutdown()
- string2 := read(t, finder.DbPath, filesystem)
+ string2 := fs.Read(t, finder.DbPath, filesystem)
if string1 != string2 {
t.Errorf("Running Finder twice generated two dbs not having identical contents.\n"+
@@ -1343,9 +1207,9 @@
func TestNumSyscallsOfSecondFind(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/misc.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/misc.txt", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1357,15 +1221,15 @@
},
)
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
filesystem.ClearMetrics()
// run the finder again and confirm it doesn't check the filesystem
refoundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, refoundPaths, foundPaths)
- assertSameStatCalls(t, filesystem.StatCalls, []string{})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameResponse(t, refoundPaths, foundPaths)
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
finder.Shutdown()
}
@@ -1373,9 +1237,9 @@
func TestChangingParamsOfSecondFind(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/metoo.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/metoo.txt", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1387,15 +1251,15 @@
},
)
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
filesystem.ClearMetrics()
// run the finder again and confirm it gets the right answer without asking the filesystem
refoundPaths := finder.FindNamedAt("/tmp", "metoo.txt")
- assertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
finder.Shutdown()
}
@@ -1403,15 +1267,15 @@
func TestSymlinkPointingToFile(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/a/ignoreme.txt", filesystem)
- link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
- link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
- link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
- link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
- link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
- link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
- link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/ignoreme.txt", filesystem)
+ fs.Link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
+ fs.Link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
+ fs.Link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
+ fs.Link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
+ fs.Link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
+ fs.Link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
+ fs.Link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1432,20 +1296,21 @@
"/tmp/d/hi.txt",
"/tmp/f/hi.txt",
}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
}
func TestSymlinkPointingToDirectory(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/dir/hi.txt", filesystem)
- create(t, "/tmp/dir/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/dir/hi.txt", filesystem)
+ fs.Create(t, "/tmp/dir/ignoreme.txt", filesystem)
- link(t, "/tmp/links/dir", "../dir", filesystem)
- link(t, "/tmp/links/link", "../dir", filesystem)
- link(t, "/tmp/links/broken", "nothingHere", filesystem)
- link(t, "/tmp/links/recursive", "recursive", filesystem)
+ fs.Link(t, "/tmp/links/dir", "../dir", filesystem)
+ fs.Link(t, "/tmp/links/link", "../dir", filesystem)
+ fs.Link(t, "/tmp/links/hi.txt", "../dir", filesystem)
+ fs.Link(t, "/tmp/links/broken", "nothingHere", filesystem)
+ fs.Link(t, "/tmp/links/recursive", "recursive", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1463,7 +1328,7 @@
correctResponse := []string{
"/tmp/dir/hi.txt",
}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
}
@@ -1472,9 +1337,9 @@
func TestAddPruneFile(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/out/hi.txt", filesystem)
- create(t, "/tmp/out/a/hi.txt", filesystem)
- create(t, "/tmp/hi.txt", filesystem)
+ fs.Create(t, "/tmp/out/hi.txt", filesystem)
+ fs.Create(t, "/tmp/out/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/hi.txt", filesystem)
// do find
finder := newFinder(
@@ -1490,7 +1355,7 @@
foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
// check result
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/hi.txt",
"/tmp/out/hi.txt",
"/tmp/out/a/hi.txt"},
@@ -1499,19 +1364,19 @@
// modify filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/out/.ignore-out-dir", filesystem)
+ fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
// run another find and check its result
finder2 := finderWithSameParams(t, finder)
foundPaths = finder2.FindNamedAt("/tmp", "hi.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
finder2.Shutdown()
}
func TestUpdatingDbIffChanged(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/b/bye.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/bye.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1526,11 +1391,11 @@
foundPaths := finder.FindAll()
finder.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/b/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/hi.txt", filesystem)
filesystem.Clock.Tick()
filesystem.ClearMetrics()
@@ -1539,10 +1404,10 @@
foundPaths = finder2.FindAll()
finder2.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
expectedDbWriteTime := filesystem.Clock.Time()
- actualDbWriteTime := modTime(t, finder2.DbPath, filesystem)
+ actualDbWriteTime := fs.ModTime(t, finder2.DbPath, filesystem)
if actualDbWriteTime != expectedDbWriteTime {
t.Fatalf("Expected to write db at %v, actually wrote db at %v\n",
expectedDbWriteTime, actualDbWriteTime)
@@ -1556,10 +1421,10 @@
foundPaths = finder3.FindAll()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
finder3.Shutdown()
- actualDbWriteTime = modTime(t, finder3.DbPath, filesystem)
+ actualDbWriteTime = fs.ModTime(t, finder3.DbPath, filesystem)
if actualDbWriteTime != expectedDbWriteTime {
t.Fatalf("Re-wrote db even when contents did not change")
}
@@ -1569,10 +1434,10 @@
func TestDirectoryNotPermitted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/hi.txt", filesystem)
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/a/a/hi.txt", filesystem)
- create(t, "/tmp/b/hi.txt", filesystem)
+ fs.Create(t, "/tmp/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/hi.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1588,12 +1453,12 @@
finder.Shutdown()
allPaths := []string{"/tmp/hi.txt", "/tmp/a/hi.txt", "/tmp/a/a/hi.txt", "/tmp/b/hi.txt"}
// check results
- assertSameResponse(t, foundPaths, allPaths)
+ fs.AssertSameResponse(t, foundPaths, allPaths)
// modify the filesystem
filesystem.Clock.Tick()
- setReadable(t, "/tmp/a", false, filesystem)
+ fs.SetReadable(t, "/tmp/a", false, filesystem)
filesystem.Clock.Tick()
// run the second finder
@@ -1601,24 +1466,24 @@
foundPaths = finder2.FindAll()
finder2.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
// modify the filesystem back
- setReadable(t, "/tmp/a", true, filesystem)
+ fs.SetReadable(t, "/tmp/a", true, filesystem)
// run the third finder
finder3 := finderWithSameParams(t, finder2)
foundPaths = finder3.FindAll()
finder3.Shutdown()
// check results
- assertSameResponse(t, foundPaths, allPaths)
+ fs.AssertSameResponse(t, foundPaths, allPaths)
}
func TestFileNotPermitted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/hi.txt", filesystem)
- setReadable(t, "/tmp/hi.txt", false, filesystem)
+ fs.Create(t, "/tmp/hi.txt", filesystem)
+ fs.SetReadable(t, "/tmp/hi.txt", false, filesystem)
// run the first finder
finder := newFinder(
@@ -1633,13 +1498,13 @@
foundPaths := finder.FindAll()
finder.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
}
func TestCacheEntryPathUnexpectedError(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1654,14 +1519,14 @@
foundPaths := finder.FindAll()
finder.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
// make the directory not readable
- setReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
+ fs.SetReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
// run the second finder
_, err := finderAndErrorWithSameParams(t, finder)
if err == nil {
- fatal(t, "Failed to detect unexpected filesystem error")
+ t.Fatal("Failed to detect unexpected filesystem error")
}
}
diff --git a/finder/fs/Android.bp b/finder/fs/Android.bp
index 27e3c7d..85929ae 100644
--- a/finder/fs/Android.bp
+++ b/finder/fs/Android.bp
@@ -22,8 +22,10 @@
srcs: [
"fs.go",
"readdir.go",
+ "test.go",
],
testSrcs: [
+ "fs_test.go",
"readdir_test.go",
],
darwin: {
@@ -37,4 +39,3 @@
],
},
}
-
diff --git a/finder/fs/fs.go b/finder/fs/fs.go
index 071f764..d2e3e4a 100644
--- a/finder/fs/fs.go
+++ b/finder/fs/fs.go
@@ -51,6 +51,7 @@
// getting information about files
Open(name string) (file io.ReadCloser, err error)
Lstat(path string) (stats os.FileInfo, err error)
+ Stat(path string) (stats os.FileInfo, err error)
ReadDir(path string) (contents []DirEntryInfo, err error)
InodeNumber(info os.FileInfo) (number uint64, err error)
@@ -99,6 +100,10 @@
return os.Lstat(path)
}
+func (osFs) Stat(path string) (stats os.FileInfo, err error) {
+ return os.Stat(path)
+}
+
func (osFs) ReadDir(path string) (contents []DirEntryInfo, err error) {
entries, err := readdir(path)
if err != nil {
@@ -376,7 +381,7 @@
size int64
modTime time.Time // time at which the inode's contents were modified
permTime time.Time // time at which the inode's permissions were modified
- isDir bool
+ mode os.FileMode
inodeNumber uint64
deviceNumber uint64
}
@@ -390,7 +395,7 @@
}
func (m *mockFileInfo) Mode() os.FileMode {
- return 0
+ return m.mode
}
func (m *mockFileInfo) ModTime() time.Time {
@@ -398,7 +403,7 @@
}
func (m *mockFileInfo) IsDir() bool {
- return m.isDir
+ return m.mode&os.ModeDir != 0
}
func (m *mockFileInfo) Sys() interface{} {
@@ -407,11 +412,11 @@
func (m *MockFs) dirToFileInfo(d *mockDir, path string) (info *mockFileInfo) {
return &mockFileInfo{
- path: path,
+ path: filepath.Base(path),
size: 1,
modTime: d.modTime,
permTime: d.permTime,
- isDir: true,
+ mode: os.ModeDir,
inodeNumber: d.inodeNumber,
deviceNumber: m.deviceNumber,
}
@@ -420,11 +425,11 @@
func (m *MockFs) fileToFileInfo(f *mockFile, path string) (info *mockFileInfo) {
return &mockFileInfo{
- path: path,
+ path: filepath.Base(path),
size: 1,
modTime: f.modTime,
permTime: f.permTime,
- isDir: false,
+ mode: 0,
inodeNumber: f.inodeNumber,
deviceNumber: m.deviceNumber,
}
@@ -432,11 +437,11 @@
func (m *MockFs) linkToFileInfo(l *mockLink, path string) (info *mockFileInfo) {
return &mockFileInfo{
- path: path,
+ path: filepath.Base(path),
size: 1,
modTime: l.modTime,
permTime: l.permTime,
- isDir: false,
+ mode: os.ModeSymlink,
inodeNumber: l.inodeNumber,
deviceNumber: m.deviceNumber,
}
@@ -485,6 +490,16 @@
}
}
+func (m *MockFs) Stat(path string) (stats os.FileInfo, err error) {
+ // resolve symlinks
+ path, err = m.resolve(path, true)
+ if err != nil {
+ return nil, err
+ }
+
+ return m.Lstat(path)
+}
+
func (m *MockFs) InodeNumber(info os.FileInfo) (number uint64, err error) {
mockInfo, ok := info.(*mockFileInfo)
if ok {
diff --git a/finder/fs/fs_test.go b/finder/fs/fs_test.go
new file mode 100644
index 0000000..22a4d7a
--- /dev/null
+++ b/finder/fs/fs_test.go
@@ -0,0 +1,76 @@
+// Copyright 2020 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 fs
+
+import (
+ "os"
+ "testing"
+)
+
+func TestMockFs_LstatStatSymlinks(t *testing.T) {
+ // setup filesystem
+ filesystem := NewMockFs(nil)
+ Create(t, "/tmp/realdir/hi.txt", filesystem)
+ Create(t, "/tmp/realdir/ignoreme.txt", filesystem)
+
+ Link(t, "/tmp/links/dir", "../realdir", filesystem)
+ Link(t, "/tmp/links/file", "../realdir/hi.txt", filesystem)
+ Link(t, "/tmp/links/broken", "nothingHere", filesystem)
+ Link(t, "/tmp/links/recursive", "recursive", filesystem)
+
+ assertStat := func(t *testing.T, stat os.FileInfo, err error, wantName string, wantMode os.FileMode) {
+ t.Helper()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if g, w := stat.Name(), wantName; g != w {
+ t.Errorf("want name %q, got %q", w, g)
+ }
+ if g, w := stat.Mode(), wantMode; g != w {
+ t.Errorf("%s: want mode %q, got %q", wantName, w, g)
+ }
+ }
+
+ assertErr := func(t *testing.T, err error, wantErr string) {
+ if err == nil || err.Error() != wantErr {
+ t.Errorf("want error %q, got %q", wantErr, err)
+ }
+ }
+
+ stat, err := filesystem.Lstat("/tmp/links/dir")
+ assertStat(t, stat, err, "dir", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/dir")
+ assertStat(t, stat, err, "realdir", os.ModeDir)
+
+ stat, err = filesystem.Lstat("/tmp/links/file")
+ assertStat(t, stat, err, "file", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/file")
+ assertStat(t, stat, err, "hi.txt", 0)
+
+ stat, err = filesystem.Lstat("/tmp/links/broken")
+ assertStat(t, stat, err, "broken", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/broken")
+ assertErr(t, err, "stat /tmp/links/nothingHere: file does not exist")
+
+ stat, err = filesystem.Lstat("/tmp/links/recursive")
+ assertStat(t, stat, err, "recursive", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/recursive")
+ assertErr(t, err, "read /tmp/links/recursive: too many levels of symbolic links")
+}
diff --git a/finder/fs/test.go b/finder/fs/test.go
new file mode 100644
index 0000000..cb2140e
--- /dev/null
+++ b/finder/fs/test.go
@@ -0,0 +1,146 @@
+// Copyright 2020 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 fs
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "reflect"
+ "sort"
+ "testing"
+ "time"
+)
+
+func Write(t *testing.T, path string, content string, filesystem *MockFs) {
+ parent := filepath.Dir(path)
+ filesystem.MkDirs(parent)
+ err := filesystem.WriteFile(path, []byte(content), 0777)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Create(t *testing.T, path string, filesystem *MockFs) {
+ Write(t, path, "hi", filesystem)
+}
+
+func Delete(t *testing.T, path string, filesystem *MockFs) {
+ err := filesystem.Remove(path)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func RemoveAll(t *testing.T, path string, filesystem *MockFs) {
+ err := filesystem.RemoveAll(path)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Move(t *testing.T, oldPath string, newPath string, filesystem *MockFs) {
+ err := filesystem.Rename(oldPath, newPath)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Link(t *testing.T, newPath string, oldPath string, filesystem *MockFs) {
+ parentPath := filepath.Dir(newPath)
+ err := filesystem.MkDirs(parentPath)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ err = filesystem.Symlink(oldPath, newPath)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Read(t *testing.T, path string, filesystem *MockFs) string {
+ reader, err := filesystem.Open(path)
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+ bytes, err := ioutil.ReadAll(reader)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ return string(bytes)
+}
+
+func ModTime(t *testing.T, path string, filesystem *MockFs) time.Time {
+ stats, err := filesystem.Lstat(path)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ return stats.ModTime()
+}
+
+func SetReadable(t *testing.T, path string, readable bool, filesystem *MockFs) {
+ err := filesystem.SetReadable(path, readable)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func SetReadErr(t *testing.T, path string, readErr error, filesystem *MockFs) {
+ err := filesystem.SetReadErr(path, readErr)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func AssertSameResponse(t *testing.T, actual []string, expected []string) {
+ t.Helper()
+ sort.Strings(actual)
+ sort.Strings(expected)
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("Expected Finder to return these %v paths:\n %v,\ninstead returned these %v paths: %v\n",
+ len(expected), expected, len(actual), actual)
+ }
+}
+
+func AssertSameStatCalls(t *testing.T, actual []string, expected []string) {
+ t.Helper()
+ sort.Strings(actual)
+ sort.Strings(expected)
+
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("Finder made incorrect Stat calls.\n"+
+ "Actual:\n"+
+ "%v\n"+
+ "Expected:\n"+
+ "%v\n"+
+ "\n",
+ actual, expected)
+ }
+}
+
+func AssertSameReadDirCalls(t *testing.T, actual []string, expected []string) {
+ t.Helper()
+ sort.Strings(actual)
+ sort.Strings(expected)
+
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("Finder made incorrect ReadDir calls.\n"+
+ "Actual:\n"+
+ "%v\n"+
+ "Expected:\n"+
+ "%v\n"+
+ "\n",
+ actual, expected)
+ }
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index f6904f1..00baa57 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -83,7 +83,6 @@
type generatorProperties struct {
// The command to run on one or more input files. Cmd supports substitution of a few variables
- // (the actual substitution is implemented in GenerateAndroidBuildActions below)
//
// Available variables for substitution:
//
@@ -94,9 +93,6 @@
// $(depfile): a file to which dependencies will be written, if the depfile property is set to true
// $(genDir): the sandbox directory for this tool; contains $(out)
// $$: a literal $
- //
- // All files used must be declared as inputs (to ensure proper up-to-date checks).
- // Use "$(in)" directly in Cmd to ensure that all inputs used are declared.
Cmd *string
// Enable reading a file containing dependencies in gcc format after the command completes
@@ -559,6 +555,12 @@
}
}
+func (g *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // Because generated outputs are checked by client modules(e.g. cc_library, ...)
+ // we can safely ignore the check here.
+ return nil
+}
+
func generatorFactory(taskGenerator taskFunc, props ...interface{}) *Module {
module := &Module{
taskGenerator: taskGenerator,
diff --git a/java/aar.go b/java/aar.go
index 074ead4..500788f 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -762,6 +762,10 @@
return a.depIsInSameApex(ctx, dep)
}
+func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ return nil
+}
+
var _ android.PrebuiltInterface = (*Import)(nil)
// android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
diff --git a/java/androidmk.go b/java/androidmk.go
index 62cf169..e73b030 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -91,7 +91,7 @@
} else {
mainEntries = android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
- DistFile: android.OptionalPathForPath(library.distFile),
+ DistFiles: library.distFiles,
OutputFile: android.OptionalPathForPath(library.outputFile),
Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
@@ -550,14 +550,14 @@
// needed because an invalid output file would prevent the make entries from
// being written.
// TODO(b/146727827): Revert when we do not need to generate stubs and API separately.
- distFile := android.OptionalPathForPath(dstubs.apiFile)
+ distFile := dstubs.apiFile
outputFile := android.OptionalPathForPath(dstubs.stubsSrcJar)
if !outputFile.Valid() {
- outputFile = distFile
+ outputFile = android.OptionalPathForPath(distFile)
}
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
- DistFile: distFile,
+ DistFiles: android.MakeDefaultDistFiles(distFile),
OutputFile: outputFile,
Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index d471fb7..075b7aa 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -156,17 +156,158 @@
}
`)
- without_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module())
- with_tag_entries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module())
+ withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_without_tag", "android_common").Module())
+ withTagEntries := android.AndroidMkEntriesForTest(t, config, "", ctx.ModuleForTests("foo_with_tag", "android_common").Module())
- if len(without_tag_entries) != 2 || len(with_tag_entries) != 2 {
- t.Errorf("two mk entries per module expected, got %d and %d", len(without_tag_entries), len(with_tag_entries))
+ if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 {
+ t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries))
}
- if !with_tag_entries[0].DistFile.Valid() || !strings.Contains(with_tag_entries[0].DistFile.String(), "/javac/foo_with_tag.jar") {
- t.Errorf("expected classes.jar DistFile, got %v", with_tag_entries[0].DistFile)
+ if len(withTagEntries[0].DistFiles[".jar"]) != 1 ||
+ !strings.Contains(withTagEntries[0].DistFiles[".jar"][0].String(), "/javac/foo_with_tag.jar") {
+ t.Errorf("expected DistFiles to contain classes.jar, got %v", withTagEntries[0].DistFiles)
}
- if without_tag_entries[0].DistFile.Valid() {
- t.Errorf("did not expect explicit DistFile, got %v", without_tag_entries[0].DistFile)
+ if len(withoutTagEntries[0].DistFiles[".jar"]) > 0 {
+ t.Errorf("did not expect explicit DistFile for .jar tag, got %v", withoutTagEntries[0].DistFiles[".jar"])
+ }
+}
+
+func TestDistWithDest(t *testing.T) {
+ ctx, config := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ compile_dex: true,
+ dist: {
+ targets: ["my_goal"],
+ dest: "my/custom/dest/dir",
+ },
+ }
+ `)
+
+ module := ctx.ModuleForTests("foo", "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, config, "", module)
+ if len(entries) != 2 {
+ t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries))
+ }
+
+ distStrings := entries[0].GetDistForGoals(module)
+
+ if len(distStrings) != 2 {
+ t.Errorf("Expected 2 entries for dist: PHONY and dist-for-goals, but got %q", distStrings)
+ }
+
+ if distStrings[0] != ".PHONY: my_goal\n" {
+ t.Errorf("Expected .PHONY entry to declare my_goal, but got: %s", distStrings[0])
+ }
+
+ if !strings.Contains(distStrings[1], "$(call dist-for-goals,my_goal") ||
+ !strings.Contains(distStrings[1], ".intermediates/foo/android_common/dex/foo.jar:my/custom/dest/dir") {
+ t.Errorf(
+ "Expected dist-for-goals entry to contain my_goal and new dest dir, but got: %s", distStrings[1])
+ }
+}
+
+func TestDistsWithAllProperties(t *testing.T) {
+ ctx, config := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ compile_dex: true,
+ dist: {
+ targets: ["baz"],
+ },
+ dists: [
+ {
+ targets: ["bar"],
+ tag: ".jar",
+ dest: "bar.jar",
+ dir: "bar/dir",
+ suffix: ".qux",
+ },
+ ]
+ }
+ `)
+
+ module := ctx.ModuleForTests("foo", "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, config, "", module)
+ if len(entries) != 2 {
+ t.Errorf("Expected 2 AndroidMk entries, got %d", len(entries))
+ }
+
+ distStrings := entries[0].GetDistForGoals(module)
+
+ if len(distStrings) != 4 {
+ t.Errorf("Expected 4 entries for dist: PHONY and dist-for-goals, but got %d", len(distStrings))
+ }
+
+ if distStrings[0] != ".PHONY: bar\n" {
+ t.Errorf("Expected .PHONY entry to declare bar, but got: %s", distStrings[0])
+ }
+
+ if !strings.Contains(distStrings[1], "$(call dist-for-goals,bar") ||
+ !strings.Contains(
+ distStrings[1],
+ ".intermediates/foo/android_common/javac/foo.jar:bar/dir/bar.qux.jar") {
+ t.Errorf(
+ "Expected dist-for-goals entry to contain bar and new dest dir, but got: %s", distStrings[1])
+ }
+
+ if distStrings[2] != ".PHONY: baz\n" {
+ t.Errorf("Expected .PHONY entry to declare baz, but got: %s", distStrings[2])
+ }
+
+ if !strings.Contains(distStrings[3], "$(call dist-for-goals,baz") ||
+ !strings.Contains(distStrings[3], ".intermediates/foo/android_common/dex/foo.jar:foo.jar") {
+ t.Errorf(
+ "Expected dist-for-goals entry to contain my_other_goal and new dest dir, but got: %s",
+ distStrings[3])
+ }
+}
+
+func TestDistsWithTag(t *testing.T) {
+ ctx, config := testJava(t, `
+ java_library {
+ name: "foo_without_tag",
+ srcs: ["a.java"],
+ compile_dex: true,
+ dists: [
+ {
+ targets: ["hi"],
+ },
+ ],
+ }
+ java_library {
+ name: "foo_with_tag",
+ srcs: ["a.java"],
+ compile_dex: true,
+ dists: [
+ {
+ targets: ["hi"],
+ tag: ".jar",
+ },
+ ],
+ }
+ `)
+
+ moduleWithoutTag := ctx.ModuleForTests("foo_without_tag", "android_common").Module()
+ moduleWithTag := ctx.ModuleForTests("foo_with_tag", "android_common").Module()
+
+ withoutTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithoutTag)
+ withTagEntries := android.AndroidMkEntriesForTest(t, config, "", moduleWithTag)
+
+ if len(withoutTagEntries) != 2 || len(withTagEntries) != 2 {
+ t.Errorf("two mk entries per module expected, got %d and %d", len(withoutTagEntries), len(withTagEntries))
+ }
+
+ distFilesWithoutTag := withoutTagEntries[0].DistFiles
+ distFilesWithTag := withTagEntries[0].DistFiles
+
+ if len(distFilesWithTag[".jar"]) != 1 ||
+ !strings.Contains(distFilesWithTag[".jar"][0].String(), "/javac/foo_with_tag.jar") {
+ t.Errorf("expected foo_with_tag's .jar-tagged DistFiles to contain classes.jar, got %v", distFilesWithTag[".jar"])
+ }
+ if len(distFilesWithoutTag[".jar"]) > 0 {
+ t.Errorf("did not expect foo_without_tag's .jar-tagged DistFiles to contain files, but got %v", distFilesWithoutTag[".jar"])
}
}
diff --git a/java/app.go b/java/app.go
index 4bb292d..37a6453 100755
--- a/java/app.go
+++ b/java/app.go
@@ -151,7 +151,7 @@
"allow-prereleased": strconv.FormatBool(proptools.Bool(as.properties.Prerelease)),
"screen-densities": screenDensities,
"sdk-version": ctx.Config().PlatformSdkVersion(),
- "stem": ctx.ModuleName(),
+ "stem": as.BaseModuleName(),
},
})
}
@@ -421,8 +421,10 @@
if String(a.deviceProperties.Min_sdk_version) == "" {
ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.")
}
+
if minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx); err == nil {
a.checkJniLibsSdkVersion(ctx, minSdkVersion)
+ android.CheckMinSdkVersion(a, ctx, int(minSdkVersion))
} else {
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
}
@@ -862,13 +864,13 @@
return jniLibs, certificates
}
-func (a *AndroidApp) walkPayloadDeps(ctx android.ModuleContext,
- do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
-
+func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
ctx.WalkDeps(func(child, parent android.Module) bool {
isExternal := !a.DepIsInSameApex(ctx, child)
if am, ok := child.(android.ApexModule); ok {
- do(ctx, parent, am, isExternal)
+ if !do(ctx, parent, am, isExternal) {
+ return false
+ }
}
return !isExternal
})
@@ -880,7 +882,7 @@
}
depsInfo := android.DepNameToDepInfoMap{}
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
depName := to.Name()
if info, exist := depsInfo[depName]; exist {
info.From = append(info.From, from.Name())
@@ -900,6 +902,7 @@
MinSdkVersion: toMinSdkVersion,
}
}
+ return true
})
a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(), depsInfo)
@@ -938,7 +941,7 @@
}
func (a *AndroidApp) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
- return ctx.Device() && (ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled())
+ return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
}
func (a *AndroidApp) PreventInstall() {
@@ -1563,6 +1566,11 @@
return sdkSpecFrom("")
}
+func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // Do not check for prebuilts against the min_sdk_version of enclosing APEX
+ return nil
+}
+
func createVariantGroupType(variants []string, variantGroupName string) reflect.Type {
props := reflect.TypeOf((*AndroidAppImportProperties)(nil))
diff --git a/java/app_test.go b/java/app_test.go
index e45ba70..120dc00 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -473,6 +473,24 @@
}
}
+func TestUpdatableApps_TransitiveDepsShouldSetMinSdkVersion(t *testing.T) {
+ testJavaError(t, `module "bar".*: should support min_sdk_version\(29\)`, cc.GatherRequiredDepsForTest(android.Android)+`
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ updatable: true,
+ sdk_version: "current",
+ min_sdk_version: "29",
+ static_libs: ["bar"],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ }
+ `)
+}
+
func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) {
testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
android_app {
diff --git a/java/config/config.go b/java/config/config.go
index 0351009..0fe74c8 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -34,7 +34,8 @@
DefaultLambdaStubsLibrary = "core-lambda-stubs"
SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar"
- DefaultJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"}
+ DefaultMakeJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"}
+ DefaultJacocoExcludeFilter = []string{"org.junit.**", "org.jacoco.**", "org.mockito.**"}
InstrumentFrameworkModules = []string{
"framework",
@@ -109,7 +110,7 @@
pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
- pctx.SourcePathVariable("GenKotlinBuildFileCmd", "build/soong/scripts/gen-kotlin-build-file.sh")
+ pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file.py")
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
pctx.SourcePathVariable("PackageCheckCmd", "build/soong/scripts/package-check.sh")
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 29f1f9b..708a72a 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -66,7 +66,7 @@
ctx.Strict("ZIPSYNC", "${ZipSyncCmd}")
ctx.Strict("JACOCO_CLI_JAR", "${JacocoCLIJar}")
- ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultJacocoExcludeFilter, ","))
+ ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultMakeJacocoExcludeFilter, ","))
ctx.Strict("EXTRACT_JAR_PACKAGES", "${ExtractJarPackagesCmd}")
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 7f1afd6..f1b7178 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -173,7 +173,7 @@
profileBootListing = android.ExistentPathForSource(ctx,
ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot")
profileIsTextListing = true
- } else {
+ } else if global.ProfileDir != "" {
profileClassListing = android.ExistentPathForSource(ctx,
global.ProfileDir, ctx.ModuleName()+".prof")
}
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 43fb964..99bfb6d 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1320,7 +1320,6 @@
cmd.Flag("--exclude-documentation-from-stubs")
}
}
- cmd.FlagWithArg("--hide ", "ShowingMemberInHiddenClass") // b/159121253 -- remove it once all the violations are fixed.
}
func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
@@ -1414,7 +1413,7 @@
}
func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
- if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
+ if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() && d.apiFile != nil {
if d.apiFile.String() == "" {
ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.")
}
@@ -1842,13 +1841,19 @@
Flag("-XDignore.symbol.file").
FlagWithArg("-doclet ", "jdiff.JDiff").
FlagWithInput("-docletpath ", jdiff).
- Flag("-quiet").
- FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())).
- FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())).
- Implicit(d.apiXmlFile).
- FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())).
- FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())).
- Implicit(d.lastReleasedApiXmlFile)
+ Flag("-quiet")
+
+ if d.apiXmlFile != nil {
+ cmd.FlagWithArg("-newapi ", strings.TrimSuffix(d.apiXmlFile.Base(), d.apiXmlFile.Ext())).
+ FlagWithArg("-newapidir ", filepath.Dir(d.apiXmlFile.String())).
+ Implicit(d.apiXmlFile)
+ }
+
+ if d.lastReleasedApiXmlFile != nil {
+ cmd.FlagWithArg("-oldapi ", strings.TrimSuffix(d.lastReleasedApiXmlFile.Base(), d.lastReleasedApiXmlFile.Ext())).
+ FlagWithArg("-oldapidir ", filepath.Dir(d.lastReleasedApiXmlFile.String())).
+ Implicit(d.lastReleasedApiXmlFile)
+ }
rule.Command().
BuiltTool(ctx, "soong_zip").
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index ce624bf..130b634 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -59,10 +59,9 @@
var _ hiddenAPIIntf = (*hiddenAPI)(nil)
-func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, dexJar android.ModuleOutPath,
+func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bool, dexJar android.ModuleOutPath,
implementationJar android.Path, uncompressDex bool) android.ModuleOutPath {
if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
- name := ctx.ModuleName()
// Modules whose names are of the format <x>-hiddenapi provide hiddenapi information
// for the boot jar module <x>. Otherwise, the module provides information for itself.
@@ -90,7 +89,14 @@
// the gathered information in the generated dex file.
if name == bootJarName {
hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", name+".jar")
- h.bootDexJarPath = dexJar
+
+ // More than one library with the same classes can be encoded but only one can
+ // be added to the global set of flags, otherwise it will result in duplicate
+ // classes which is an error. Therefore, only add the dex jar of one of them
+ // to the global set of flags.
+ if primary {
+ h.bootDexJarPath = dexJar
+ }
hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex)
dexJar = hiddenAPIJar
}
diff --git a/java/jacoco.go b/java/jacoco.go
index bce9822..9162161 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -25,6 +25,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/java/config"
)
var (
@@ -76,7 +77,8 @@
if err != nil {
ctx.PropertyErrorf("jacoco.include_filter", "%s", err.Error())
}
- excludes, err := jacocoFiltersToSpecs(j.properties.Jacoco.Exclude_filter)
+ // Also include the default list of classes to exclude from instrumentation.
+ excludes, err := jacocoFiltersToSpecs(append(j.properties.Jacoco.Exclude_filter, config.DefaultJacocoExcludeFilter...))
if err != nil {
ctx.PropertyErrorf("jacoco.exclude_filter", "%s", err.Error())
}
diff --git a/java/java.go b/java/java.go
index cb2ae28..0d46672 100644
--- a/java/java.go
+++ b/java/java.go
@@ -44,7 +44,7 @@
PropertyName: "java_libs",
},
func(j *Library) android.Path {
- implementationJars := j.ImplementationJars()
+ implementationJars := j.ImplementationAndResourcesJars()
if len(implementationJars) != 1 {
panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
}
@@ -342,6 +342,12 @@
// otherwise provides defaults libraries to add to the bootclasspath.
System_modules *string
+ // The name of the module as used in build configuration.
+ //
+ // Allows a library to separate its actual name from the name used in
+ // build configuration, e.g.ctx.Config().BootJars().
+ ConfigurationName *string `blueprint:"mutated"`
+
// set the name of the output
Stem *string
@@ -479,7 +485,7 @@
// list of the xref extraction files
kytheFiles android.Paths
- distFile android.Path
+ distFiles android.TaggedDistFiles
// Collect the module directory for IDE info in java/jdeps.go.
modulePaths []string
@@ -1632,8 +1638,11 @@
return
}
+ configurationName := j.ConfigurationName()
+ primary := configurationName == ctx.ModuleName()
+
// Hidden API CSV generation and dex encoding
- dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
+ dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile,
proptools.Bool(j.deviceProperties.Uncompress_dex))
// merge dex jar with resources if necessary
@@ -1888,10 +1897,32 @@
return j.depIsInSameApex(ctx, dep)
}
+func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ sdkSpec := j.minSdkVersion()
+ if !sdkSpec.specified() {
+ return fmt.Errorf("min_sdk_version is not specified")
+ }
+ if sdkSpec.kind == sdkCore {
+ return nil
+ }
+ ver, err := sdkSpec.effectiveVersion(ctx)
+ if err != nil {
+ return err
+ }
+ if int(ver) > sdkVersion {
+ return fmt.Errorf("newer SDK(%v)", ver)
+ }
+ return nil
+}
+
func (j *Module) Stem() string {
return proptools.StringDefault(j.deviceProperties.Stem, j.Name())
}
+func (j *Module) ConfigurationName() string {
+ return proptools.StringDefault(j.deviceProperties.ConfigurationName, j.BaseModuleName())
+}
+
func (j *Module) JacocoReportClassesFile() android.Path {
return j.jacocoReportClassesFile
}
@@ -1904,18 +1935,9 @@
// Java libraries (.jar file)
//
-type LibraryProperties struct {
- Dist struct {
- // The tag of the output of this module that should be output.
- Tag *string `android:"arch_variant"`
- } `android:"arch_variant"`
-}
-
type Library struct {
Module
- libraryProperties LibraryProperties
-
InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.Paths)
}
@@ -1977,14 +1999,7 @@
j.Stem()+".jar", j.outputFile, extraInstallDeps...)
}
- // Verify Dist.Tag is set to a supported output
- if j.libraryProperties.Dist.Tag != nil {
- distFiles, err := j.OutputFiles(*j.libraryProperties.Dist.Tag)
- if err != nil {
- ctx.PropertyErrorf("dist.tag", "%s", err.Error())
- }
- j.distFile = distFiles[0]
- }
+ j.distFiles = j.GenerateTaggedDistFiles(ctx)
}
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -2102,7 +2117,6 @@
module := &Library{}
module.addHostAndDeviceProperties()
- module.AddProperties(&module.libraryProperties)
module.initModuleAndImport(&module.ModuleBase)
@@ -2652,6 +2666,11 @@
return j.depIsInSameApex(ctx, dep)
}
+func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // Do not check for prebuilts against the min_sdk_version of enclosing APEX
+ return nil
+}
+
// Add compile time check for interface implementation
var _ android.IDEInfo = (*Import)(nil)
var _ android.IDECustomizedModuleName = (*Import)(nil)
@@ -2821,6 +2840,11 @@
return j.dexJarFile
}
+func (j *DexImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // we don't check prebuilt modules for sdk_version
+ return nil
+}
+
// dex_import imports a `.jar` file containing classes.dex files.
//
// A dex_import module cannot be used as a dependency of a java_* or android_* module, it can only be installed
@@ -2893,6 +2917,7 @@
&appProperties{},
&appTestProperties{},
&overridableAppProperties{},
+ &testProperties{},
&ImportProperties{},
&AARImportProperties{},
&sdkLibraryProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index 1d07e70..def42db 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -25,6 +25,7 @@
"strings"
"testing"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -171,6 +172,20 @@
}
}
+func checkModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+ t.Helper()
+ module := ctx.ModuleForTests(name, variant).Module()
+ deps := []string{}
+ ctx.VisitDirectDeps(module, func(m blueprint.Module) {
+ deps = append(deps, m.Name())
+ })
+ sort.Strings(deps)
+
+ if actual := deps; !reflect.DeepEqual(expected, actual) {
+ t.Errorf("expected %#q, found %#q", expected, actual)
+ }
+}
+
func TestJavaLinkType(t *testing.T) {
testJava(t, `
java_library {
@@ -630,6 +645,90 @@
t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
}
}
+
+ checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `prebuilt_sdklib.stubs.source.test`,
+ `prebuilt_sdklib.stubs.system`,
+ `prebuilt_sdklib.stubs.test`,
+ })
+}
+
+func TestJavaSdkLibraryImport_WithSource(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `)
+
+ checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `prebuilt_sdklib`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+
+ checkModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ `sdklib.impl`,
+ // This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
+ // dependency is added after prebuilts may have been renamed and so has to use
+ // the renamed name.
+ `sdklib.stubs`,
+ `sdklib.xml`,
+ })
+}
+
+func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ prefer: true,
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `)
+
+ checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `prebuilt_sdklib`,
+ // This should be sdklib.stubs but is switched to the prebuilt because it is preferred.
+ `prebuilt_sdklib.stubs`,
+ `sdklib.impl`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+
+ checkModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `sdklib.impl`,
+ `sdklib.xml`,
+ })
}
func TestDefaults(t *testing.T) {
@@ -1379,6 +1478,28 @@
`)
}
+func TestJavaSdkLibrary_Deps(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+ `)
+
+ checkModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+}
+
func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
testJava(t, `
java_sdk_library_import {
diff --git a/java/kotlin.go b/java/kotlin.go
index 673970b..e3356be 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -31,7 +31,9 @@
Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
`mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath "$name" $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
+ ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
+ ` --out "$kotlinBuildFile" && ` +
`${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` +
`-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` +
`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` +
@@ -74,7 +76,7 @@
Inputs: srcFiles,
Implicits: deps,
Args: map[string]string{
- "classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"),
+ "classpath": flags.kotlincClasspath.FormJavaClassPath(""),
"kotlincFlags": flags.kotlincFlags,
"srcJars": strings.Join(srcJars.Strings(), " "),
"classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(),
@@ -93,7 +95,9 @@
Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` +
`mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath "$name" "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
+ ` --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
+ ` --out "$kotlinBuildFile" && ` +
`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` +
`-Xplugin=${config.KotlinKaptJar} ` +
`-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` +
@@ -162,7 +166,7 @@
Inputs: srcFiles,
Implicits: deps,
Args: map[string]string{
- "classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"),
+ "classpath": flags.kotlincClasspath.FormJavaClassPath(""),
"kotlincFlags": flags.kotlincFlags,
"srcJars": strings.Join(srcJars.Strings(), " "),
"srcJarDir": android.PathForModuleOut(ctx, "kapt", "srcJars").String(),
diff --git a/java/lint.go b/java/lint.go
index fac9a19..b73d6a5 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -88,7 +88,7 @@
}
func (l *linter) writeLintProjectXML(ctx android.ModuleContext,
- rule *android.RuleBuilder) (projectXMLPath, configXMLPath, cacheDir android.WritablePath, deps android.Paths) {
+ rule *android.RuleBuilder) (projectXMLPath, configXMLPath, cacheDir, homeDir android.WritablePath, deps android.Paths) {
var resourcesList android.WritablePath
if len(l.resources) > 0 {
@@ -106,6 +106,7 @@
// Lint looks for a lint.xml file next to the project.xml file, give it one.
configXMLPath = android.PathForModuleOut(ctx, "lint", "lint.xml")
cacheDir = android.PathForModuleOut(ctx, "lint", "cache")
+ homeDir = android.PathForModuleOut(ctx, "lint", "home")
srcJarDir := android.PathForModuleOut(ctx, "lint-srcjars")
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
@@ -154,8 +155,11 @@
cmd.FlagForEachArg("--extra_checks_jar ", l.extraLintCheckJars.Strings())
deps = append(deps, l.extraLintCheckJars...)
- // The cache tag in project.xml is relative to the project.xml file.
- cmd.FlagWithArg("--cache_dir ", "cache")
+ cmd.FlagWithArg("--root_dir ", "$PWD")
+
+ // The cache tag in project.xml is relative to the root dir, or the project.xml file if
+ // the root dir is not set.
+ cmd.FlagWithArg("--cache_dir ", cacheDir.String())
cmd.FlagWithInput("@",
android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
@@ -165,7 +169,7 @@
cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
- return projectXMLPath, configXMLPath, cacheDir, deps
+ return projectXMLPath, configXMLPath, cacheDir, homeDir, deps
}
// generateManifest adds a command to the rule to write a dummy manifest cat contains the
@@ -207,18 +211,19 @@
l.manifest = manifest
}
- projectXML, lintXML, cacheDir, deps := l.writeLintProjectXML(ctx, rule)
+ projectXML, lintXML, cacheDir, homeDir, deps := l.writeLintProjectXML(ctx, rule)
l.outputs.html = android.PathForModuleOut(ctx, "lint-report.html")
l.outputs.text = android.PathForModuleOut(ctx, "lint-report.txt")
l.outputs.xml = android.PathForModuleOut(ctx, "lint-report.xml")
- rule.Command().Text("rm -rf").Flag(cacheDir.String())
- rule.Command().Text("mkdir -p").Flag(cacheDir.String())
+ rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
+ rule.Command().Text("mkdir -p").Flag(cacheDir.String()).Flag(homeDir.String())
rule.Command().
Text("(").
Flag("JAVA_OPTS=-Xmx2048m").
+ FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()).
FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath(ctx)).
FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXmlPath(ctx)).
Tool(android.PathForSource(ctx, "prebuilts/cmdline-tools/tools/bin/lint")).
@@ -239,7 +244,7 @@
Text("|| (").Text("cat").Input(l.outputs.text).Text("; exit 7)").
Text(")")
- rule.Command().Text("rm -rf").Flag(cacheDir.String())
+ rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
rule.Build(pctx, ctx, "lint", "lint")
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 782c94a..8f8f8ce 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1087,15 +1087,22 @@
// Creates the implementation java library
func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) {
+
+ moduleNamePtr := proptools.StringPtr(module.BaseModuleName())
+
props := struct {
- Name *string
- Visibility []string
- Instrument bool
+ Name *string
+ Visibility []string
+ Instrument bool
+ ConfigurationName *string
}{
Name: proptools.StringPtr(module.implLibraryModuleName()),
Visibility: module.sdkLibraryProperties.Impl_library_visibility,
// Set the instrument property to ensure it is instrumented when instrumentation is required.
Instrument: true,
+
+ // Make the created library behave as if it had the same name as this module.
+ ConfigurationName: moduleNamePtr,
}
properties := []interface{}{
@@ -1905,6 +1912,11 @@
return false
}
+func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // we don't check prebuilt modules for sdk_version
+ return nil
+}
+
func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
return module.commonOutputFiles(tag)
}
@@ -2071,6 +2083,11 @@
// do nothing
}
+func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked
+ return nil
+}
+
// File path to the runtime implementation library
func (module *sdkLibraryXml) implPath() string {
implName := proptools.String(module.properties.Lib_name)
@@ -2193,8 +2210,12 @@
properties.Jars = jars
properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope)
properties.StubsSrcJar = paths.stubsSrcJar.Path()
- properties.CurrentApiFile = paths.currentApiFilePath.Path()
- properties.RemovedApiFile = paths.removedApiFilePath.Path()
+ if paths.currentApiFilePath.Valid() {
+ properties.CurrentApiFile = paths.currentApiFilePath.Path()
+ }
+ if paths.removedApiFilePath.Valid() {
+ properties.RemovedApiFile = paths.removedApiFilePath.Path()
+ }
s.Scopes[apiScope] = properties
}
}
diff --git a/python/python.go b/python/python.go
index 8b912be..a6c9e2a 100644
--- a/python/python.go
+++ b/python/python.go
@@ -251,6 +251,18 @@
return android.OptionalPathForPath(p.installer.(*binaryDecorator).path)
}
+func (p *Module) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ if outputFile := p.installSource; outputFile.Valid() {
+ return android.Paths{outputFile.Path()}, nil
+ }
+ return android.Paths{}, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
func (p *Module) isEmbeddedLauncherEnabled(actual_version string) bool {
switch actual_version {
case pyVersion2:
diff --git a/rust/Android.bp b/rust/Android.bp
index b06ea8e..d56de87 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -9,24 +9,26 @@
],
srcs: [
"androidmk.go",
- "compiler.go",
- "coverage.go",
"binary.go",
"builder.go",
+ "clippy.go",
+ "compiler.go",
+ "coverage.go",
"library.go",
"prebuilt.go",
"proc_macro.go",
- "project_json.go",
+ "project_json.go",
"rust.go",
"test.go",
"testing.go",
],
testSrcs: [
"binary_test.go",
+ "clippy_test.go",
"compiler_test.go",
"coverage_test.go",
"library_test.go",
- "project_json_test.go",
+ "project_json_test.go",
"rust_test.go",
"test_test.go",
],
diff --git a/rust/OWNERS b/rust/OWNERS
index afd06e4..b5b795c 100644
--- a/rust/OWNERS
+++ b/rust/OWNERS
@@ -1,5 +1,5 @@
# Additional owner/reviewers for rust rules, including parent directory owners.
-per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, srhines@google.com
+per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, mmaurer@google.com, srhines@google.com
# Limited owners/reviewers of the allowed list.
-per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com
+per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, mmaurer@google.com, srhines@google.com
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 69d0df5..aea899b 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -86,8 +86,11 @@
func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
ctx.subAndroidMk(ret, binary.baseCompiler)
+ if binary.distFile.Valid() {
+ ret.DistFiles = android.MakeDefaultDistFiles(binary.distFile.Path())
+ }
+
ret.Class = "EXECUTABLES"
- ret.DistFile = binary.distFile
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
if binary.coverageOutputZipFile.Valid() {
@@ -127,7 +130,10 @@
ret.Class = "SHARED_LIBRARIES"
}
- ret.DistFile = library.distFile
+ if library.distFile.Valid() {
+ ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path())
+ }
+
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
if !library.rlib() {
fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
@@ -143,7 +149,9 @@
ctx.subAndroidMk(ret, procMacro.baseCompiler)
ret.Class = "PROC_MACRO_LIBRARIES"
- ret.DistFile = procMacro.distFile
+ if procMacro.distFile.Valid() {
+ ret.DistFiles = android.MakeDefaultDistFiles(procMacro.distFile.Path())
+ }
}
diff --git a/rust/builder.go b/rust/builder.go
index 7dbb59d..8bc11bb 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -39,6 +39,18 @@
},
"rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
+ _ = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver")
+ clippyDriver = pctx.AndroidStaticRule("clippy",
+ blueprint.RuleParams{
+ Command: "$clippyCmd " +
+ // Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
+ // Use the metadata output as it has the smallest footprint.
+ "--emit metadata -o $out $in ${libFlags} " +
+ "$clippyFlags $rustcFlags",
+ CommandDeps: []string{"$clippyCmd"},
+ },
+ "rustcFlags", "libFlags", "clippyFlags")
+
zip = pctx.AndroidStaticRule("zip",
blueprint.RuleParams{
Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
@@ -57,36 +69,36 @@
pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
}
-func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath, includeDirs []string) buildOutput {
flags.RustFlags = append(flags.RustFlags, "-C lto")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", includeDirs)
}
-func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath, includeDirs []string) buildOutput {
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", includeDirs)
}
-func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath, includeDirs []string) buildOutput {
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", includeDirs)
}
-func TransformSrctoStatic(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath, includeDirs []string) buildOutput {
flags.RustFlags = append(flags.RustFlags, "-C lto")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", includeDirs)
}
-func TransformSrctoShared(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath, includeDirs []string) buildOutput {
flags.RustFlags = append(flags.RustFlags, "-C lto")
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", includeDirs)
}
-func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps,
+func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps,
flags Flags, outputFile android.WritablePath, includeDirs []string) buildOutput {
return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", includeDirs)
}
@@ -99,7 +111,7 @@
return paths
}
-func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps PathDeps, flags Flags,
+func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath, crate_type string, includeDirs []string) buildOutput {
var inputs android.Paths
@@ -109,8 +121,8 @@
var implicitOutputs android.WritablePaths
output.outputFile = outputFile
- crate_name := ctx.(ModuleContext).CrateName()
- targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
+ crate_name := ctx.RustModule().CrateName()
+ targetTriple := ctx.toolchain().RustTriple()
inputs = append(inputs, main)
@@ -125,10 +137,14 @@
rustcFlags = append(rustcFlags, "--target="+targetTriple)
linkFlags = append(linkFlags, "-target "+targetTriple)
}
- // TODO once we have static libraries in the host prebuilt .bp, this
- // should be unconditionally added.
- if !(ctx.Host() && ctx.TargetPrimary()) {
- // If we're not targeting the host primary arch, do not use an implicit sysroot
+ // TODO(b/159718669): Once we have defined static libraries in the host
+ // prebuilts Blueprint file, sysroot should be unconditionally sourced
+ // from /dev/null. Explicitly set sysroot to avoid clippy-driver to
+ // internally call rustc.
+ if ctx.Host() && ctx.TargetPrimary() {
+ rustcFlags = append(rustcFlags, "--sysroot=${config.RustPath}")
+ } else {
+ // If we're not targeting the host primary arch, do not use a sysroot.
rustcFlags = append(rustcFlags, "--sysroot=/dev/null")
}
// Collect linker flags
@@ -179,6 +195,25 @@
output.coverageFile = gcnoFile
}
+ if flags.Clippy {
+ clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: clippyDriver,
+ Description: "clippy " + main.Rel(),
+ Output: clippyFile,
+ ImplicitOutputs: nil,
+ Inputs: inputs,
+ Implicits: implicits,
+ Args: map[string]string{
+ "rustcFlags": strings.Join(rustcFlags, " "),
+ "libFlags": strings.Join(libFlags, " "),
+ "clippyFlags": strings.Join(flags.ClippyFlags, " "),
+ },
+ })
+ // Declare the clippy build as an implicit dependency of the original crate.
+ implicits = append(implicits, clippyFile)
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: rustc,
Description: "rustc " + main.Rel(),
@@ -198,7 +233,7 @@
return output
}
-func TransformCoverageFilesToZip(ctx android.ModuleContext,
+func TransformCoverageFilesToZip(ctx ModuleContext,
covFiles android.Paths, baseName string) android.OptionalPath {
if len(covFiles) > 0 {
diff --git a/rust/clippy.go b/rust/clippy.go
new file mode 100644
index 0000000..e1f567d
--- /dev/null
+++ b/rust/clippy.go
@@ -0,0 +1,42 @@
+// Copyright 2020 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.
+
+package rust
+
+import (
+ "android/soong/rust/config"
+)
+
+type ClippyProperties struct {
+ // whether to run clippy.
+ Clippy *bool
+}
+
+type clippy struct {
+ Properties ClippyProperties
+}
+
+func (c *clippy) props() []interface{} {
+ return []interface{}{&c.Properties}
+}
+
+func (c *clippy) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+ if c.Properties.Clippy != nil && !*c.Properties.Clippy {
+ return flags, deps
+ }
+ enabled, lints := config.ClippyLintsForDir(ctx.ModuleDir())
+ flags.Clippy = enabled
+ flags.ClippyFlags = append(flags.ClippyFlags, lints)
+ return flags, deps
+}
diff --git a/rust/clippy_test.go b/rust/clippy_test.go
new file mode 100644
index 0000000..af5cd17
--- /dev/null
+++ b/rust/clippy_test.go
@@ -0,0 +1,46 @@
+// Copyright 2020 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.
+
+package rust
+
+import (
+ "testing"
+)
+
+func TestClippy(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }
+ rust_library {
+ name: "libfoobar",
+ srcs: ["foo.rs"],
+ crate_name: "foobar",
+ clippy: false,
+ }`)
+
+ ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Output("libfoo.so")
+ fooClippy := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").MaybeRule("clippy")
+ if fooClippy.Rule.String() != "android/soong/rust.clippy" {
+ t.Errorf("Clippy output (default) for libfoo was not generated: %+v", fooClippy)
+ }
+
+ ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_shared").Output("libfoobar.so")
+ foobarClippy := ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_shared").MaybeRule("clippy")
+ if foobarClippy.Rule != nil {
+ t.Errorf("Clippy output for libfoobar is not empty")
+ }
+}
diff --git a/rust/compiler.go b/rust/compiler.go
index efc1ce4..050a259 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -253,7 +253,7 @@
}
func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
- stem := ctx.baseModuleName()
+ stem := ctx.ModuleName()
if String(compiler.Properties.Stem) != "" {
stem = String(compiler.Properties.Stem)
}
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index 5026da3..1d30f82 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -9,6 +9,7 @@
"arm_device.go",
"arm64_device.go",
"global.go",
+ "clippy.go",
"toolchain.go",
"allowed_list.go",
"x86_darwin_host.go",
diff --git a/rust/config/clippy.go b/rust/config/clippy.go
new file mode 100644
index 0000000..c199ff2
--- /dev/null
+++ b/rust/config/clippy.go
@@ -0,0 +1,80 @@
+// Copyright 2020 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.
+
+package config
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var (
+ defaultLints = []string{
+ "-D missing-docs",
+ "-D clippy::missing-safety-doc",
+ }
+ defaultVendorLints = []string{
+ "",
+ }
+)
+
+func init() {
+ // Default Rust lints. These apply to all Google-authored modules.
+ pctx.VariableFunc("ClippyDefaultLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("CLIPPY_DEFAULT_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultLints, " ")
+ })
+
+ // Rust lints that only applies to external code.
+ pctx.VariableFunc("ClippyVendorLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("CLIPPY_VENDOR_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultVendorLints, " ")
+ })
+}
+
+type PathBasedClippyConfig struct {
+ PathPrefix string
+ Enabled bool
+ ClippyConfig string
+}
+
+const clippyNone = ""
+const clippyDefault = "${config.ClippyDefaultLints}"
+const clippyVendor = "${config.ClippyVendorLints}"
+
+// This is a map of local path prefixes to a boolean indicating if the lint
+// rule should be generated and if so, the set of lints to use. The first entry
+// matching will be used. If no entry is matching, clippyDefault will be used.
+var DefaultLocalTidyChecks = []PathBasedClippyConfig{
+ {"external/", false, clippyNone},
+ {"hardware/", true, clippyVendor},
+ {"prebuilts/", false, clippyNone},
+ {"vendor/google", true, clippyDefault},
+ {"vendor/", true, clippyVendor},
+}
+
+// ClippyLintsForDir returns the Clippy lints to be used for a repository.
+func ClippyLintsForDir(dir string) (bool, string) {
+ for _, pathCheck := range DefaultLocalTidyChecks {
+ if strings.HasPrefix(dir, pathCheck.PathPrefix) {
+ return pathCheck.Enabled, pathCheck.ClippyConfig
+ }
+ }
+ return true, clippyDefault
+}
diff --git a/rust/config/global.go b/rust/config/global.go
index 63624c0..663514d 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.43.0"
+ RustDefaultVersion = "1.44.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/rust/coverage.go b/rust/coverage.go
index 9be57dc..223ba4f 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -45,7 +45,7 @@
func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
- if !ctx.DeviceConfig().NativeCoverageEnabled() && !ctx.DeviceConfig().ClangCoverageEnabled() {
+ if !ctx.DeviceConfig().NativeCoverageEnabled() {
return flags, deps
}
@@ -67,6 +67,6 @@
// Host coverage not yet supported.
} else {
// Update useSdk and sdkVersion args if Rust modules become SDK aware.
- cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), false, "")
+ cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.RustModule().nativeCoverage(), false, "")
}
}
diff --git a/rust/library.go b/rust/library.go
index 3c948ea..f070c34 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -329,7 +329,7 @@
}
func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
- flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.baseModuleName())
+ flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
flags = library.baseCompiler.compilerFlags(ctx, flags)
if library.shared() || library.static() {
library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
diff --git a/rust/rust.go b/rust/rust.go
index 7b82b1f..6c60348 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -49,8 +49,10 @@
GlobalLinkFlags []string // Flags that apply globally to linker
RustFlags []string // Flags that apply to rust
LinkFlags []string // Flags that apply to linker
+ ClippyFlags []string // Flags that apply to clippy-driver, during the linting
Toolchain config.Toolchain
Coverage bool
+ Clippy bool
}
type BaseProperties struct {
@@ -75,6 +77,7 @@
compiler compiler
coverage *coverage
+ clippy *clippy
cachedToolchain config.Toolchain
subAndroidMkOnce map[subAndroidMkProvider]bool
outputFile android.OptionalPath
@@ -306,6 +309,7 @@
&PrebuiltProperties{},
&TestProperties{},
&cc.CoverageProperties{},
+ &ClippyProperties{},
)
android.InitDefaultsModule(module)
@@ -456,6 +460,9 @@
if mod.coverage != nil {
mod.AddProperties(mod.coverage.props()...)
}
+ if mod.clippy != nil {
+ mod.AddProperties(mod.clippy.props()...)
+ }
android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
@@ -487,6 +494,7 @@
func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
module := newBaseModule(hod, multilib)
module.coverage = &coverage{}
+ module.clippy = &clippy{}
return module
}
@@ -506,39 +514,50 @@
}
type ModuleContextIntf interface {
+ RustModule() *Module
toolchain() config.Toolchain
- baseModuleName() string
- CrateName() string
- nativeCoverage() bool
}
type depsContext struct {
android.BottomUpMutatorContext
- moduleContextImpl
}
type moduleContext struct {
android.ModuleContext
- moduleContextImpl
}
-func (ctx *moduleContextImpl) nativeCoverage() bool {
- return ctx.mod.nativeCoverage()
+type baseModuleContext struct {
+ android.BaseModuleContext
+}
+
+func (ctx *moduleContext) RustModule() *Module {
+ return ctx.Module().(*Module)
+}
+
+func (ctx *moduleContext) toolchain() config.Toolchain {
+ return ctx.RustModule().toolchain(ctx)
+}
+
+func (ctx *depsContext) RustModule() *Module {
+ return ctx.Module().(*Module)
+}
+
+func (ctx *depsContext) toolchain() config.Toolchain {
+ return ctx.RustModule().toolchain(ctx)
+}
+
+func (ctx *baseModuleContext) RustModule() *Module {
+ return ctx.Module().(*Module)
+}
+
+func (ctx *baseModuleContext) toolchain() config.Toolchain {
+ return ctx.RustModule().toolchain(ctx)
}
func (mod *Module) nativeCoverage() bool {
return mod.compiler != nil && mod.compiler.nativeCoverage()
}
-type moduleContextImpl struct {
- mod *Module
- ctx BaseModuleContext
-}
-
-func (ctx *moduleContextImpl) toolchain() config.Toolchain {
- return ctx.mod.toolchain(ctx.ctx)
-}
-
func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
if mod.cachedToolchain == nil {
mod.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
@@ -552,11 +571,7 @@
func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
ctx := &moduleContext{
ModuleContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: mod,
- },
}
- ctx.ctx = ctx
toolchain := mod.toolchain(ctx)
@@ -576,6 +591,9 @@
if mod.coverage != nil {
flags, deps = mod.coverage.flags(ctx, flags, deps)
}
+ if mod.clippy != nil {
+ flags, deps = mod.clippy.flags(ctx, flags, deps)
+ }
if mod.compiler != nil {
outputFile := mod.compiler.compile(ctx, flags, deps)
@@ -607,14 +625,6 @@
}
-func (ctx *moduleContextImpl) baseModuleName() string {
- return ctx.mod.ModuleBase.BaseModuleName()
-}
-
-func (ctx *moduleContextImpl) CrateName() string {
- return ctx.mod.CrateName()
-}
-
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
@@ -811,11 +821,7 @@
func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
ctx := &depsContext{
BottomUpMutatorContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: mod,
- },
}
- ctx.ctx = ctx
deps := mod.deps(ctx)
commonDepVariations := []blueprint.Variation{}
@@ -862,19 +868,10 @@
}
}
-type baseModuleContext struct {
- android.BaseModuleContext
- moduleContextImpl
-}
-
func (mod *Module) beginMutator(actx android.BottomUpMutatorContext) {
ctx := &baseModuleContext{
BaseModuleContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: mod,
- },
}
- ctx.ctx = ctx
mod.begin(ctx)
}
@@ -889,6 +886,18 @@
return name
}
+var _ android.HostToolProvider = (*Module)(nil)
+
+func (mod *Module) HostToolPath() android.OptionalPath {
+ if !mod.Host() {
+ return android.OptionalPath{}
+ }
+ if _, ok := mod.compiler.(*binaryDecorator); ok {
+ return mod.outputFile
+ }
+ return android.OptionalPath{}
+}
+
var Bool = proptools.Bool
var BoolDefault = proptools.BoolDefault
var String = proptools.String
diff --git a/rust/rust_test.go b/rust/rust_test.go
index fe21e3a..280c22a 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -88,11 +88,11 @@
config := testConfig(bp)
if coverage {
+ config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
config.TestProductVariables.NativeCoveragePaths = []string{"*"}
}
- t.Helper()
ctx := CreateTestContext()
ctx.Register(config)
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 1f55030..d962a41 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -106,7 +106,7 @@
py3: {
enabled: false,
},
- }
+ },
}
python_binary_host {
@@ -152,5 +152,17 @@
python_binary_host {
name: "lint-project-xml",
main: "lint-project-xml.py",
- srcs: ["lint-project-xml.py"],
+ srcs: [
+ "lint-project-xml.py",
+ "ninja_rsp.py",
+ ],
+}
+
+python_binary_host {
+ name: "gen-kotlin-build-file.py",
+ main: "gen-kotlin-build-file.py",
+ srcs: [
+ "gen-kotlin-build-file.py",
+ "ninja_rsp.py",
+ ],
}
diff --git a/scripts/OWNERS b/scripts/OWNERS
index dd0966f..0274554 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1,3 +1,4 @@
per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
+per-file construct_context.sh = ngeoffray@google.com,calin@google.com,mathieuc@google.com,skvadrik@google.com
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index 9b68a82..1bc78e6 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -23,6 +23,15 @@
runtime-module-host-exports
i18n-module-test-exports
i18n-module-sdk
+ platform-mainline-sdk
+ platform-mainline-host-exports
+)
+
+# List of libraries installed on the platform that are needed for ART chroot
+# testing.
+PLATFORM_LIBRARIES=(
+ liblog
+ libartpalette-system
)
# We want to create apex modules for all supported architectures.
@@ -49,7 +58,8 @@
for product in "${PRODUCTS[@]}"; do
echo_and_run build/soong/soong_ui.bash --make-mode $@ \
TARGET_PRODUCT=${product} \
- ${MAINLINE_MODULES[@]}
+ ${MAINLINE_MODULES[@]} \
+ ${PLATFORM_LIBRARIES[@]}
PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT)
TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH)
@@ -58,9 +68,11 @@
for module in "${MAINLINE_MODULES[@]}"; do
echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/
done
+ for library in "${PLATFORM_LIBRARIES[@]}"; do
+ echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/lib/${library}.so ${DIST_DIR}/${TARGET_ARCH}/
+ done
done
-
# Create multi-archs SDKs in a different out directory. The multi-arch script
# uses Soong in --skip-make mode which cannot use the same directory as normal
# mode with make.
diff --git a/scripts/construct_context.sh b/scripts/construct_context.sh
new file mode 100755
index 0000000..d620d08
--- /dev/null
+++ b/scripts/construct_context.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 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.
+
+set -e
+
+# target_sdk_version: parsed from manifest
+#
+# outputs
+# class_loader_context_arg: final class loader conext arg
+# stored_class_loader_context_arg: final stored class loader context arg
+
+if [ -z "${target_sdk_version}" ]; then
+ echo "ERROR: target_sdk_version not set"
+ exit 2
+fi
+
+# The hidl.manager shared library has a dependency on hidl.base. We'll manually
+# add that information to the class loader context if we see those libraries.
+hidl_manager="android.hidl.manager-V1.0-java"
+hidl_base="android.hidl.base-V1.0-java"
+
+function add_to_contexts {
+ for i in $1; do
+ if [[ -z "${class_loader_context}" ]]; then
+ export class_loader_context="PCL[$i]"
+ else
+ export class_loader_context+="#PCL[$i]"
+ fi
+ if [[ $i == *"$hidl_manager"* ]]; then
+ export class_loader_context+="{PCL[${i/$hidl_manager/$hidl_base}]}"
+ fi
+ done
+
+ for i in $2; do
+ if [[ -z "${stored_class_loader_context}" ]]; then
+ export stored_class_loader_context="PCL[$i]"
+ else
+ export stored_class_loader_context+="#PCL[$i]"
+ fi
+ if [[ $i == *"$hidl_manager"* ]]; then
+ export stored_class_loader_context+="{PCL[${i/$hidl_manager/$hidl_base}]}"
+ fi
+ done
+}
+
+# The order below must match what the package manager also computes for
+# class loader context.
+
+if [[ "${target_sdk_version}" -lt "28" ]]; then
+ add_to_contexts "${conditional_host_libs_28}" "${conditional_target_libs_28}"
+fi
+
+if [[ "${target_sdk_version}" -lt "29" ]]; then
+ add_to_contexts "${conditional_host_libs_29}" "${conditional_target_libs_29}"
+fi
+
+if [[ "${target_sdk_version}" -lt "30" ]]; then
+ add_to_contexts "${conditional_host_libs_30}" "${conditional_target_libs_30}"
+fi
+
+add_to_contexts "${dex_preopt_host_libraries}" "${dex_preopt_target_libraries}"
+
+# Generate the actual context string.
+export class_loader_context_arg="--class-loader-context=PCL[]{${class_loader_context}}"
+export stored_class_loader_context_arg="--stored-class-loader-context=PCL[]{${stored_class_loader_context}}"
diff --git a/scripts/gen-kotlin-build-file.py b/scripts/gen-kotlin-build-file.py
new file mode 100644
index 0000000..83b4cd8
--- /dev/null
+++ b/scripts/gen-kotlin-build-file.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018 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.
+
+# Generates kotlinc module xml file to drive kotlinc
+
+import argparse
+import os
+
+from ninja_rsp import NinjaRspFileReader
+
+def parse_args():
+ """Parse commandline arguments."""
+
+ def convert_arg_line_to_args(arg_line):
+ for arg in arg_line.split():
+ if arg.startswith('#'):
+ return
+ if not arg.strip():
+ continue
+ yield arg
+
+ parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
+ parser.convert_arg_line_to_args = convert_arg_line_to_args
+ parser.add_argument('--out', dest='out',
+ help='file to which the module.xml contents will be written.')
+ parser.add_argument('--classpath', dest='classpath', action='append', default=[],
+ help='classpath to pass to kotlinc.')
+ parser.add_argument('--name', dest='name',
+ help='name of the module.')
+ parser.add_argument('--out_dir', dest='out_dir',
+ help='directory to which kotlinc will write output files.')
+ parser.add_argument('--srcs', dest='srcs', action='append', default=[],
+ help='file containing whitespace separated list of source files.')
+ parser.add_argument('--common_srcs', dest='common_srcs', action='append', default=[],
+ help='file containing whitespace separated list of common multiplatform source files.')
+
+ return parser.parse_args()
+
+def main():
+ """Program entry point."""
+ args = parse_args()
+
+ if not args.out:
+ raise RuntimeError('--out argument is required')
+
+ if not args.name:
+ raise RuntimeError('--name argument is required')
+
+ with open(args.out, 'w') as f:
+ # Print preamble
+ f.write('<modules>\n')
+ f.write(' <module name="%s" type="java-production" outputDir="%s">\n' % (args.name, args.out_dir or ''))
+
+ # Print classpath entries
+ for c in args.classpath:
+ for entry in c.split(':'):
+ path = os.path.abspath(entry)
+ f.write(' <classpath path="%s"/>\n' % path)
+
+ # For each rsp file, print source entries
+ for rsp_file in args.srcs:
+ for src in NinjaRspFileReader(rsp_file):
+ path = os.path.abspath(src)
+ if src.endswith('.java'):
+ f.write(' <javaSourceRoots path="%s"/>\n' % path)
+ elif src.endswith('.kt'):
+ f.write(' <sources path="%s"/>\n' % path)
+ else:
+ raise RuntimeError('unknown source file type %s' % file)
+
+ for rsp_file in args.common_srcs:
+ for src in NinjaRspFileReader(rsp_file):
+ path = os.path.abspath(src)
+ f.write(' <sources path="%s"/>\n' % path)
+ f.write(' <commonSources path="%s"/>\n' % path)
+
+ f.write(' </module>\n')
+ f.write('</modules>\n')
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/gen-kotlin-build-file.sh b/scripts/gen-kotlin-build-file.sh
deleted file mode 100755
index 177ca1b..0000000
--- a/scripts/gen-kotlin-build-file.sh
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2018 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.
-
-# Generates kotlinc module xml file to standard output based on rsp files
-
-if [[ -z "$1" ]]; then
- echo "usage: $0 <classpath> <name> <outDir> <rspFiles>..." >&2
- exit 1
-fi
-
-# Classpath variable has a tendency to be prefixed by "-classpath", remove it.
-if [[ $1 == "-classpath" ]]; then
- shift
-fi;
-
-classpath=$1
-name=$2
-out_dir=$3
-shift 3
-
-# Path in the build file may be relative to the build file, we need to make them
-# absolute
-prefix="$(pwd)"
-
-get_abs_path () {
- local file="$1"
- if [[ "${file:0:1}" == '/' ]] ; then
- echo "${file}"
- else
- echo "${prefix}/${file}"
- fi
-}
-
-# Print preamble
-echo "<modules><module name=\"${name}\" type=\"java-production\" outputDir=\"${out_dir}\">"
-
-# Print classpath entries
-for file in $(echo "$classpath" | tr ":" "\n"); do
- path="$(get_abs_path "$file")"
- echo " <classpath path=\"${path}\"/>"
-done
-
-# For each rsp file, print source entries
-while (( "$#" )); do
- for file in $(cat "$1"); do
- path="$(get_abs_path "$file")"
- if [[ $file == *.java ]]; then
- echo " <javaSourceRoots path=\"${path}\"/>"
- elif [[ $file == *.kt ]]; then
- echo " <sources path=\"${path}\"/>"
- else
- echo "Unknown source file type ${file}"
- exit 1
- fi
- done
-
- shift
-done
-
-echo "</module></modules>"
diff --git a/scripts/lint-project-xml.py b/scripts/lint-project-xml.py
index 7ab4f01..f1ef85d 100755
--- a/scripts/lint-project-xml.py
+++ b/scripts/lint-project-xml.py
@@ -19,6 +19,8 @@
import argparse
+from ninja_rsp import NinjaRspFileReader
+
def check_action(check_type):
"""
@@ -77,6 +79,8 @@
help='mark the module as a test.')
parser.add_argument('--cache_dir', dest='cache_dir',
help='directory to use for cached file.')
+ parser.add_argument('--root_dir', dest='root_dir',
+ help='directory to use for root dir.')
group = parser.add_argument_group('check arguments', 'later arguments override earlier ones.')
group.add_argument('--fatal_check', dest='checks', action=check_action('fatal'), default=[],
help='treat a lint issue as a fatal error.')
@@ -89,79 +93,13 @@
return parser.parse_args()
-class NinjaRspFileReader:
- """
- Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
- non-standard character by surrounding the whole entry with single quotes, and then replacing
- any single quotes in the entry with the escape sequence '\''.
- """
-
- def __init__(self, filename):
- self.f = open(filename, 'r')
- self.r = self.character_reader(self.f)
-
- def __iter__(self):
- return self
-
- def character_reader(self, f):
- """Turns a file into a generator that returns one character at a time."""
- while True:
- c = f.read(1)
- if c:
- yield c
- else:
- return
-
- def __next__(self):
- entry = self.read_entry()
- if entry:
- return entry
- else:
- raise StopIteration
-
- def read_entry(self):
- c = next(self.r, "")
- if not c:
- return ""
- elif c == "'":
- return self.read_quoted_entry()
- else:
- entry = c
- for c in self.r:
- if c == " " or c == "\n":
- break
- entry += c
- return entry
-
- def read_quoted_entry(self):
- entry = ""
- for c in self.r:
- if c == "'":
- # Either the end of the quoted entry, or the beginning of an escape sequence, read the next
- # character to find out.
- c = next(self.r)
- if not c or c == " " or c == "\n":
- # End of the item
- return entry
- elif c == "\\":
- # Escape sequence, expect a '
- c = next(self.r)
- if c != "'":
- # Malformed escape sequence
- raise "malformed escape sequence %s'\\%s" % (entry, c)
- entry += "'"
- else:
- raise "malformed escape sequence %s'%s" % (entry, c)
- else:
- entry += c
- raise "unterminated quoted entry %s" % entry
-
-
def write_project_xml(f, args):
test_attr = "test='true' " if args.test else ""
f.write("<?xml version='1.0' encoding='utf-8'?>\n")
f.write("<project>\n")
+ if args.root_dir:
+ f.write(" <root dir='%s' />\n" % args.root_dir)
f.write(" <module name='%s' android='true' %sdesugar='full' >\n" % (args.name, "library='true' " if args.library else ""))
if args.manifest:
f.write(" <manifest file='%s' %s/>\n" % (args.manifest, test_attr))
diff --git a/scripts/ninja_rsp.py b/scripts/ninja_rsp.py
new file mode 100644
index 0000000..004ce47
--- /dev/null
+++ b/scripts/ninja_rsp.py
@@ -0,0 +1,83 @@
+# Copyright (C) 2020 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.
+#
+
+"""This file reads entries from a Ninja rsp file."""
+
+class NinjaRspFileReader:
+ """
+ Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
+ non-standard character by surrounding the whole entry with single quotes, and then replacing
+ any single quotes in the entry with the escape sequence '\''.
+ """
+
+ def __init__(self, filename):
+ self.f = open(filename, 'r')
+ self.r = self.character_reader(self.f)
+
+ def __iter__(self):
+ return self
+
+ def character_reader(self, f):
+ """Turns a file into a generator that returns one character at a time."""
+ while True:
+ c = f.read(1)
+ if c:
+ yield c
+ else:
+ return
+
+ def __next__(self):
+ entry = self.read_entry()
+ if entry:
+ return entry
+ else:
+ raise StopIteration
+
+ def read_entry(self):
+ c = next(self.r, "")
+ if not c:
+ return ""
+ elif c == "'":
+ return self.read_quoted_entry()
+ else:
+ entry = c
+ for c in self.r:
+ if c == " " or c == "\n":
+ break
+ entry += c
+ return entry
+
+ def read_quoted_entry(self):
+ entry = ""
+ for c in self.r:
+ if c == "'":
+ # Either the end of the quoted entry, or the beginning of an escape sequence, read the next
+ # character to find out.
+ c = next(self.r)
+ if not c or c == " " or c == "\n":
+ # End of the item
+ return entry
+ elif c == "\\":
+ # Escape sequence, expect a '
+ c = next(self.r)
+ if c != "'":
+ # Malformed escape sequence
+ raise "malformed escape sequence %s'\\%s" % (entry, c)
+ entry += "'"
+ else:
+ raise "malformed escape sequence %s'%s" % (entry, c)
+ else:
+ entry += c
+ raise "unterminated quoted entry %s" % entry
diff --git a/scripts/rustfmt.toml b/scripts/rustfmt.toml
new file mode 100644
index 0000000..617d425
--- /dev/null
+++ b/scripts/rustfmt.toml
@@ -0,0 +1,5 @@
+# Android Format Style
+
+edition = "2018"
+use_small_heuristics = "Max"
+newline_style = "Unix"
diff --git a/scripts/transitive-deps.sh b/scripts/transitive-deps.sh
index c6f8b76..ba36ba4 100755
--- a/scripts/transitive-deps.sh
+++ b/scripts/transitive-deps.sh
@@ -56,7 +56,7 @@
temporary / intermediate files.
-sep=<delim> Use 'delim' as output field separator between notice
checksum and notice filename in notice output.
- e.g. sep='\t'
+ e.g. sep='\\t'
(Default space)
-csv Shorthand for -sep=','
-directories=<f> Output directory names of dependencies to 'f'.
@@ -280,7 +280,7 @@
notices=)
notices_out=$(expr "${flag}" : '^.*=\(.*\)$');;
*)
- die "Unknown flag ${1}";;
+ die "${usage}\n\nUnknown flag ${1}";;
esac
;;
*)
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 77a4e94..7496b20 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -23,6 +23,7 @@
fs := map[string][]byte{
"Test.java": nil,
+ "resource.test": nil,
"aidl/foo/bar/Test.aidl": nil,
// For java_sdk_library
@@ -348,6 +349,7 @@
java_library {
name: "myjavalib",
srcs: ["Test.java"],
+ java_resources: ["resource.txt"],
aidl: {
export_include_dirs: ["aidl"],
},
@@ -381,7 +383,7 @@
`),
checkAllCopyRules(`
-.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/myjavalib.jar
+.intermediates/myjavalib/android_common/withres/myjavalib.jar -> java/myjavalib.jar
aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl
`),
)
diff --git a/sdk/sdk.go b/sdk/sdk.go
index cb5a605..b9b8199 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -291,7 +291,7 @@
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "FAKE",
OutputFile: s.snapshotFile,
- DistFile: s.snapshotFile,
+ DistFiles: android.MakeDefaultDistFiles(s.snapshotFile.Path()),
Include: "$(BUILD_PHONY_PACKAGE)",
ExtraFooters: []android.AndroidMkExtraFootersFunc{
func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 7bb267d..f28b2b6 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -107,6 +107,8 @@
testProperties TestProperties
+ installDir android.InstallPath
+
data android.Paths
testConfig android.Path
}
@@ -176,13 +178,13 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
+ entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
},
},
}}
}
func (s *ShBinary) customAndroidMkEntries(entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
entries.SetString("LOCAL_MODULE_SUFFIX", "")
entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel())
if len(s.properties.Symlinks) > 0 {
@@ -201,8 +203,14 @@
} else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
testDir = filepath.Join(testDir, ctx.Arch().ArchType.String())
}
- installDir := android.PathForModuleInstall(ctx, testDir, proptools.String(s.properties.Sub_dir))
- s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
+ if s.SubDir() != "" {
+ // Don't add the module name to the installation path if sub_dir is specified for backward
+ // compatibility.
+ s.installDir = android.PathForModuleInstall(ctx, testDir, s.SubDir())
+ } else {
+ s.installDir = android.PathForModuleInstall(ctx, testDir, s.Name())
+ }
+ s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath)
s.data = android.PathsForModuleSrc(ctx, s.testProperties.Data)
@@ -229,7 +237,7 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
-
+ entries.SetPath("LOCAL_MODULE_PATH", s.installDir.ToMakePath())
entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
if s.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig)
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 6c0d96a..3bfe611 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -55,7 +55,27 @@
return ctx, config
}
-func TestShTestTestData(t *testing.T) {
+func TestShTestSubDir(t *testing.T) {
+ ctx, config := testShBinary(t, `
+ sh_test {
+ name: "foo",
+ src: "test.sh",
+ sub_dir: "foo_test"
+ }
+ `)
+
+ mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
+
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+
+ expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo_test"
+ actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
+ if expectedPath != actualPath {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
+ }
+}
+
+func TestShTest(t *testing.T) {
ctx, config := testShBinary(t, `
sh_test {
name: "foo",
@@ -71,10 +91,17 @@
mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
- expected := []string{":testdata/data1", ":testdata/sub/data2"}
- actual := entries.EntryMap["LOCAL_TEST_DATA"]
- if !reflect.DeepEqual(expected, actual) {
- t.Errorf("Unexpected test data expected: %q, actual: %q", expected, actual)
+
+ expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo"
+ actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
+ if expectedPath != actualPath {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
+ }
+
+ expectedData := []string{":testdata/data1", ":testdata/sub/data2"}
+ actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+ if !reflect.DeepEqual(expectedData, actualData) {
+ t.Errorf("Unexpected test data expected: %q, actual: %q", expectedData, actualData)
}
}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 9f27647..768c8e5 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -310,6 +310,10 @@
}}
}
+func (m *syspropLibrary) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ return fmt.Errorf("sysprop_library is not supposed to be part of apex modules")
+}
+
// sysprop_library creates schematized APIs from sysprop description files (.sysprop).
// Both Java and C++ modules can link against sysprop_library, and API stability check
// against latest APIs (see build/soong/scripts/freeze-sysprop-api-files.sh)
diff --git a/ui/build/build.go b/ui/build/build.go
index 89c3fad..396f54c 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -243,6 +243,8 @@
// Write combined ninja file
createCombinedBuildNinjaFile(ctx, config)
+ distGzipFile(ctx, config, config.CombinedNinjaFile())
+
if what&RunBuildTests != 0 {
testForDanglingRules(ctx, config)
}
@@ -256,3 +258,47 @@
runNinja(ctx, config)
}
}
+
+// distGzipFile writes a compressed copy of src to the distDir if dist is enabled. Failures
+// are printed but non-fatal.
+func distGzipFile(ctx Context, config Config, src string, subDirs ...string) {
+ if !config.Dist() {
+ return
+ }
+
+ subDir := filepath.Join(subDirs...)
+ destDir := filepath.Join(config.DistDir(), "soong_ui", subDir)
+
+ err := os.MkdirAll(destDir, 0777)
+ if err != nil {
+ ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
+
+ }
+
+ err = gzipFileToDir(src, destDir)
+ if err != nil {
+ ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
+ }
+}
+
+// distFile writes a copy of src to the distDir if dist is enabled. Failures are printed but
+// non-fatal.
+func distFile(ctx Context, config Config, src string, subDirs ...string) {
+ if !config.Dist() {
+ return
+ }
+
+ subDir := filepath.Join(subDirs...)
+ destDir := filepath.Join(config.DistDir(), "soong_ui", subDir)
+
+ err := os.MkdirAll(destDir, 0777)
+ if err != nil {
+ ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
+
+ }
+
+ _, err = copyFile(src, filepath.Join(destDir, filepath.Base(src)))
+ if err != nil {
+ ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
+ }
+}
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 0f34b5e..6786337 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -86,7 +86,7 @@
os.MkdirAll(dumpDir, 0777)
androidMks := f.FindFirstNamedAt(".", "Android.mk")
- err := dumpListToFile(androidMks, filepath.Join(dumpDir, "Android.mk.list"))
+ err := dumpListToFile(ctx, config, androidMks, filepath.Join(dumpDir, "Android.mk.list"))
if err != nil {
ctx.Fatalf("Could not export module list: %v", err)
}
@@ -94,25 +94,25 @@
androidProductsMks := f.FindNamedAt("device", "AndroidProducts.mk")
androidProductsMks = append(androidProductsMks, f.FindNamedAt("vendor", "AndroidProducts.mk")...)
androidProductsMks = append(androidProductsMks, f.FindNamedAt("product", "AndroidProducts.mk")...)
- err = dumpListToFile(androidProductsMks, filepath.Join(dumpDir, "AndroidProducts.mk.list"))
+ err = dumpListToFile(ctx, config, androidProductsMks, filepath.Join(dumpDir, "AndroidProducts.mk.list"))
if err != nil {
ctx.Fatalf("Could not export product list: %v", err)
}
cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk")
- err = dumpListToFile(cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list"))
+ err = dumpListToFile(ctx, config, cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list"))
if err != nil {
ctx.Fatalf("Could not export module list: %v", err)
}
owners := f.FindNamedAt(".", "OWNERS")
- err = dumpListToFile(owners, filepath.Join(dumpDir, "OWNERS.list"))
+ err = dumpListToFile(ctx, config, owners, filepath.Join(dumpDir, "OWNERS.list"))
if err != nil {
ctx.Fatalf("Could not find OWNERS: %v", err)
}
testMappings := f.FindNamedAt(".", "TEST_MAPPING")
- err = dumpListToFile(testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list"))
+ err = dumpListToFile(ctx, config, testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list"))
if err != nil {
ctx.Fatalf("Could not find TEST_MAPPING: %v", err)
}
@@ -122,18 +122,24 @@
if len(androidBps) == 0 {
ctx.Fatalf("No Android.bp found")
}
- err = dumpListToFile(androidBps, filepath.Join(dumpDir, "Android.bp.list"))
+ err = dumpListToFile(ctx, config, androidBps, filepath.Join(dumpDir, "Android.bp.list"))
if err != nil {
ctx.Fatalf("Could not find modules: %v", err)
}
}
-func dumpListToFile(list []string, filePath string) (err error) {
+func dumpListToFile(ctx Context, config Config, list []string, filePath string) (err error) {
desiredText := strings.Join(list, "\n")
desiredBytes := []byte(desiredText)
actualBytes, readErr := ioutil.ReadFile(filePath)
if readErr != nil || !bytes.Equal(desiredBytes, actualBytes) {
err = ioutil.WriteFile(filePath, desiredBytes, 0777)
+ if err != nil {
+ return err
+ }
}
- return err
+
+ distFile(ctx, config, filePath, "module_paths")
+
+ return nil
}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index 2eb7850..1cd5fea 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -156,6 +156,8 @@
runKati(ctx, config, katiBuildSuffix, args, func(env *Environment) {})
+ distGzipFile(ctx, config, config.KatiBuildNinjaFile())
+
cleanCopyHeaders(ctx, config)
cleanOldInstalledFiles(ctx, config)
}
@@ -251,6 +253,8 @@
env.Set("DIST_DIR", config.DistDir())
}
})
+
+ distGzipFile(ctx, config, config.KatiPackageNinjaFile())
}
func runKatiCleanSpec(ctx Context, config Config) {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 6a12add..749acb3 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -139,6 +139,13 @@
soongBuildMetrics := loadSoongBuildMetrics(ctx, config)
logSoongBuildMetrics(ctx, soongBuildMetrics)
+ distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
+
+ if !config.SkipMake() {
+ distGzipFile(ctx, config, config.SoongAndroidMk(), "soong")
+ distGzipFile(ctx, config, config.SoongMakeVarsMk(), "soong")
+ }
+
if ctx.Metrics != nil {
ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
}
diff --git a/ui/build/util.go b/ui/build/util.go
index d44cd6d..d4c3431 100644
--- a/ui/build/util.go
+++ b/ui/build/util.go
@@ -15,6 +15,8 @@
package build
import (
+ "compress/gzip"
+ "fmt"
"io"
"os"
"path/filepath"
@@ -142,3 +144,29 @@
return io.Copy(destination, source)
}
+
+// gzipFileToDir writes a compressed copy of src to destDir with the suffix ".gz".
+func gzipFileToDir(src, destDir string) error {
+ in, err := os.Open(src)
+ if err != nil {
+ return fmt.Errorf("failed to open %s: %s", src, err.Error())
+ }
+ defer in.Close()
+
+ dest := filepath.Join(destDir, filepath.Base(src)+".gz")
+
+ out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, 0666)
+ if err != nil {
+ return fmt.Errorf("failed to open %s: %s", dest, err.Error())
+ }
+ defer out.Close()
+ gz := gzip.NewWriter(out)
+ defer gz.Close()
+
+ _, err = io.Copy(gz, in)
+ if err != nil {
+ return fmt.Errorf("failed to gzip %s: %s", dest, err.Error())
+ }
+
+ return nil
+}
diff --git a/zip/Android.bp b/zip/Android.bp
index 259e010..5081e91 100644
--- a/zip/Android.bp
+++ b/zip/Android.bp
@@ -27,7 +27,6 @@
"rate_limit.go",
],
testSrcs: [
- "zip_test.go",
+ "zip_test.go",
],
}
-