Merge "Update jacoco command line flags for latest version"
diff --git a/Android.bp b/Android.bp
index ebf1038..ba71789 100644
--- a/Android.bp
+++ b/Android.bp
@@ -51,6 +51,7 @@
"android/module.go",
"android/mutator.go",
"android/namespace.go",
+ "android/neverallow.go",
"android/onceper.go",
"android/package_ctx.go",
"android/paths.go",
diff --git a/android/arch.go b/android/arch.go
index 3a22569..e696a0d 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -119,12 +119,12 @@
func RegisterArchVariantFeatures(arch ArchType, variant string, features ...string) {
checkCalledFromInit()
- if variant != "" && !inList(variant, archVariants[arch]) {
+ if variant != "" && !InList(variant, archVariants[arch]) {
panic(fmt.Errorf("Invalid variant %q for arch %q", variant, arch))
}
for _, feature := range features {
- if !inList(feature, archFeatures[arch]) {
+ if !InList(feature, archFeatures[arch]) {
panic(fmt.Errorf("Invalid feature %q for arch %q variant %q", feature, arch, variant))
}
}
@@ -481,13 +481,13 @@
if os.Linux() {
target := "Linux_" + archType.Name
- if !inList(target, targets) {
+ if !InList(target, targets) {
targets = append(targets, target)
}
}
if os.Bionic() {
target := "Bionic_" + archType.Name
- if !inList(target, targets) {
+ if !InList(target, targets) {
targets = append(targets, target)
}
}
diff --git a/android/config.go b/android/config.go
index 887291d..07e25f3 100644
--- a/android/config.go
+++ b/android/config.go
@@ -690,12 +690,12 @@
func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
coverage := false
if c.config.ProductVariables.CoveragePaths != nil {
- if prefixInList(path, *c.config.ProductVariables.CoveragePaths) {
+ if PrefixInList(path, *c.config.ProductVariables.CoveragePaths) {
coverage = true
}
}
if coverage && c.config.ProductVariables.CoverageExcludePaths != nil {
- if prefixInList(path, *c.config.ProductVariables.CoverageExcludePaths) {
+ if PrefixInList(path, *c.config.ProductVariables.CoverageExcludePaths) {
coverage = false
}
}
@@ -706,21 +706,21 @@
if c.ProductVariables.IntegerOverflowExcludePaths == nil {
return false
}
- return prefixInList(path, *c.ProductVariables.IntegerOverflowExcludePaths)
+ return PrefixInList(path, *c.ProductVariables.IntegerOverflowExcludePaths)
}
func (c *config) CFIDisabledForPath(path string) bool {
if c.ProductVariables.CFIExcludePaths == nil {
return false
}
- return prefixInList(path, *c.ProductVariables.CFIExcludePaths)
+ return PrefixInList(path, *c.ProductVariables.CFIExcludePaths)
}
func (c *config) CFIEnabledForPath(path string) bool {
if c.ProductVariables.CFIIncludePaths == nil {
return false
}
- return prefixInList(path, *c.ProductVariables.CFIIncludePaths)
+ return PrefixInList(path, *c.ProductVariables.CFIIncludePaths)
}
func stringSlice(s *[]string) []string {
diff --git a/android/module.go b/android/module.go
index cb068ab..0fb9479 100644
--- a/android/module.go
+++ b/android/module.go
@@ -139,6 +139,7 @@
VisitDirectDepsBlueprint(visit func(blueprint.Module))
VisitDirectDeps(visit func(Module))
+ VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
VisitDepsDepthFirst(visit func(Module))
VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
@@ -831,6 +832,16 @@
})
}
+func (a *androidModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
+ a.ModuleContext.VisitDirectDeps(func(module blueprint.Module) {
+ if aModule := a.validateAndroidModule(module); aModule != nil {
+ if a.ModuleContext.OtherModuleDependencyTag(aModule) == tag {
+ visit(aModule)
+ }
+ }
+ })
+}
+
func (a *androidModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
a.ModuleContext.VisitDirectDepsIf(
// pred
diff --git a/android/mutator.go b/android/mutator.go
index 876d161..2f13f6c 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -92,6 +92,7 @@
var postDeps = []RegisterMutatorFunc{
RegisterPrebuiltsPostDepsMutators,
+ registerNeverallowMutator,
}
func PreArchMutators(f RegisterMutatorFunc) {
@@ -126,6 +127,7 @@
GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
VisitDirectDeps(visit func(Module))
+ VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
VisitDepsDepthFirst(visit func(Module))
VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
@@ -229,6 +231,16 @@
})
}
+func (a *androidTopDownMutatorContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
+ a.TopDownMutatorContext.VisitDirectDeps(func(module blueprint.Module) {
+ if aModule, _ := module.(Module); aModule != nil {
+ if a.TopDownMutatorContext.OtherModuleDependencyTag(aModule) == tag {
+ visit(aModule)
+ }
+ }
+ })
+}
+
func (a *androidTopDownMutatorContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
a.TopDownMutatorContext.VisitDirectDepsIf(
// pred
diff --git a/android/neverallow.go b/android/neverallow.go
new file mode 100644
index 0000000..261f2ee
--- /dev/null
+++ b/android/neverallow.go
@@ -0,0 +1,273 @@
+// Copyright 2017 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 android
+
+import (
+ "path/filepath"
+ "reflect"
+ "strconv"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+// "neverallow" rules for the build system.
+//
+// This allows things which aren't related to the build system and are enforced
+// for sanity, in progress code refactors, or policy to be expressed in a
+// straightforward away disjoint from implementations and tests which should
+// work regardless of these restrictions.
+//
+// A module is disallowed if all of the following are true:
+// - it is in one of the "in" paths
+// - it is not in one of the "notIn" paths
+// - it has all "with" properties matched
+// - - values are matched in their entirety
+// - - nil is interpreted as an empty string
+// - - nested properties are separated with a '.'
+// - - if the property is a list, any of the values in the list being matches
+// counts as a match
+// - it has none of the "without" properties matched (same rules as above)
+
+func registerNeverallowMutator(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("neverallow", neverallowMutator).Parallel()
+}
+
+var neverallows = []*rule{
+ neverallow().in("vendor", "device").with("vndk.enabled", "true").
+ because("the VNDK can never contain a library that is device dependent."),
+ neverallow().with("vndk.enabled", "true").without("owner", "").
+ because("a VNDK module can never have an owner."),
+ neverallow().notIn("libcore").with("no_standard_libs", "true"),
+
+ // TODO(b/67974785): always enforce the manifest
+ neverallow().
+ without("name", "libhidltransport").
+ with("product_variables.enforce_vintf_manifest.cflags", "*").
+ because("manifest enforcement should be independent of ."),
+
+ // TODO(b/67975799): vendor code should always use /vendor/bin/sh
+ neverallow().
+ without("name", "libc_bionic_ndk").
+ with("product_variables.treble_linker_namespaces.cflags", "*").
+ because("nothing should care if linker namespaces are enabled or not"),
+
+ // Example:
+ // *neverallow().with("Srcs", "main.cpp"),
+}
+
+func neverallowMutator(ctx BottomUpMutatorContext) {
+ m, ok := ctx.Module().(Module)
+ if !ok {
+ return
+ }
+
+ dir := ctx.ModuleDir() + "/"
+ properties := m.GetProperties()
+
+ for _, n := range neverallows {
+ if !n.appliesToPath(dir) {
+ continue
+ }
+
+ if !n.appliesToProperties(properties) {
+ continue
+ }
+
+ ctx.ModuleErrorf("violates " + n.String())
+ }
+}
+
+type ruleProperty struct {
+ fields []string // e.x.: Vndk.Enabled
+ value string // e.x.: true
+}
+
+type rule struct {
+ // User string for why this is a thing.
+ reason string
+
+ paths []string
+ unlessPaths []string
+
+ props []ruleProperty
+ unlessProps []ruleProperty
+}
+
+func neverallow() *rule {
+ return &rule{}
+}
+func (r *rule) in(path ...string) *rule {
+ r.paths = append(r.paths, cleanPaths(path)...)
+ return r
+}
+func (r *rule) notIn(path ...string) *rule {
+ r.unlessPaths = append(r.unlessPaths, cleanPaths(path)...)
+ return r
+}
+func (r *rule) with(properties, value string) *rule {
+ r.props = append(r.props, ruleProperty{
+ fields: fieldNamesForProperties(properties),
+ value: value,
+ })
+ return r
+}
+func (r *rule) without(properties, value string) *rule {
+ r.unlessProps = append(r.unlessProps, ruleProperty{
+ fields: fieldNamesForProperties(properties),
+ value: value,
+ })
+ return r
+}
+func (r *rule) because(reason string) *rule {
+ r.reason = reason
+ return r
+}
+
+func (r *rule) String() string {
+ s := "neverallow"
+ for _, v := range r.paths {
+ s += " dir:" + v + "*"
+ }
+ for _, v := range r.unlessPaths {
+ s += " -dir:" + v + "*"
+ }
+ for _, v := range r.props {
+ s += " " + strings.Join(v.fields, ".") + "=" + v.value
+ }
+ for _, v := range r.unlessProps {
+ s += " -" + strings.Join(v.fields, ".") + "=" + v.value
+ }
+ if len(r.reason) != 0 {
+ s += " which is restricted because " + r.reason
+ }
+ return s
+}
+
+func (r *rule) appliesToPath(dir string) bool {
+ includePath := len(r.paths) == 0 || hasAnyPrefix(dir, r.paths)
+ excludePath := hasAnyPrefix(dir, r.unlessPaths)
+ return includePath && !excludePath
+}
+
+func (r *rule) appliesToProperties(properties []interface{}) bool {
+ includeProps := hasAllProperties(properties, r.props)
+ excludeProps := hasAnyProperty(properties, r.unlessProps)
+ return includeProps && !excludeProps
+}
+
+// assorted utils
+
+func cleanPaths(paths []string) []string {
+ res := make([]string, len(paths))
+ for i, v := range paths {
+ res[i] = filepath.Clean(v) + "/"
+ }
+ return res
+}
+
+func fieldNamesForProperties(propertyNames string) []string {
+ names := strings.Split(propertyNames, ".")
+ for i, v := range names {
+ names[i] = proptools.FieldNameForProperty(v)
+ }
+ return names
+}
+
+func hasAnyPrefix(s string, prefixes []string) bool {
+ for _, prefix := range prefixes {
+ if strings.HasPrefix(s, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+func hasAnyProperty(properties []interface{}, props []ruleProperty) bool {
+ for _, v := range props {
+ if hasProperty(properties, v) {
+ return true
+ }
+ }
+ return false
+}
+
+func hasAllProperties(properties []interface{}, props []ruleProperty) bool {
+ for _, v := range props {
+ if !hasProperty(properties, v) {
+ return false
+ }
+ }
+ return true
+}
+
+func hasProperty(properties []interface{}, prop ruleProperty) bool {
+ for _, propertyStruct := range properties {
+ propertiesValue := reflect.ValueOf(propertyStruct).Elem()
+ for _, v := range prop.fields {
+ if !propertiesValue.IsValid() {
+ break
+ }
+ propertiesValue = propertiesValue.FieldByName(v)
+ }
+ if !propertiesValue.IsValid() {
+ continue
+ }
+
+ check := func(v string) bool {
+ return prop.value == "*" || prop.value == v
+ }
+
+ if matchValue(propertiesValue, check) {
+ return true
+ }
+ }
+ return false
+}
+
+func matchValue(value reflect.Value, check func(string) bool) bool {
+ if !value.IsValid() {
+ return false
+ }
+
+ if value.Kind() == reflect.Ptr {
+ if value.IsNil() {
+ return check("")
+ }
+ value = value.Elem()
+ }
+
+ switch value.Kind() {
+ case reflect.String:
+ return check(value.String())
+ case reflect.Bool:
+ return check(strconv.FormatBool(value.Bool()))
+ case reflect.Int:
+ return check(strconv.FormatInt(value.Int(), 10))
+ case reflect.Slice:
+ slice, ok := value.Interface().([]string)
+ if !ok {
+ panic("Can only handle slice of string")
+ }
+ for _, v := range slice {
+ if check(v) {
+ return true
+ }
+ }
+ return false
+ }
+
+ panic("Can't handle type: " + value.Kind().String())
+}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index d3f9704..9356aab 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -109,13 +109,11 @@
p.properties.UsePrebuilt = p.usePrebuilt(ctx, nil)
}
} else if s, ok := ctx.Module().(Module); ok {
- ctx.VisitDirectDeps(func(m Module) {
- if ctx.OtherModuleDependencyTag(m) == prebuiltDepTag {
- p := m.(PrebuiltInterface).Prebuilt()
- if p.usePrebuilt(ctx, s) {
- p.properties.UsePrebuilt = true
- s.SkipInstall()
- }
+ ctx.VisitDirectDepsWithTag(prebuiltDepTag, func(m Module) {
+ p := m.(PrebuiltInterface).Prebuilt()
+ if p.usePrebuilt(ctx, s) {
+ p.properties.UsePrebuilt = true
+ s.SkipInstall()
}
})
}
diff --git a/android/util.go b/android/util.go
index 29bb9b1..854d782 100644
--- a/android/util.go
+++ b/android/util.go
@@ -54,7 +54,7 @@
return s
}
-func indexList(s string, list []string) int {
+func IndexList(s string, list []string) int {
for i, l := range list {
if l == s {
return i
@@ -64,11 +64,11 @@
return -1
}
-func inList(s string, list []string) bool {
- return indexList(s, list) != -1
+func InList(s string, list []string) bool {
+ return IndexList(s, list) != -1
}
-func prefixInList(s string, list []string) bool {
+func PrefixInList(s string, list []string) bool {
for _, prefix := range list {
if strings.HasPrefix(s, prefix) {
return true
@@ -77,6 +77,37 @@
return false
}
+func FilterList(list []string, filter []string) (remainder []string, filtered []string) {
+ for _, l := range list {
+ if InList(l, filter) {
+ filtered = append(filtered, l)
+ } else {
+ remainder = append(remainder, l)
+ }
+ }
+
+ return
+}
+
+func RemoveListFromList(list []string, filter_out []string) (result []string) {
+ result = make([]string, 0, len(list))
+ for _, l := range list {
+ if !InList(l, filter_out) {
+ result = append(result, l)
+ }
+ }
+ return
+}
+
+func RemoveFromList(s string, list []string) (bool, []string) {
+ i := IndexList(s, list)
+ if i != -1 {
+ return true, append(list[:i], list[i+1:]...)
+ } else {
+ return false, list
+ }
+}
+
// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
// each. It modifies the slice contents in place, and returns a subslice of the original slice.
func FirstUniqueStrings(list []string) []string {
diff --git a/cc/coverage.go b/cc/coverage.go
index d2eede2..391b118 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -59,11 +59,7 @@
// For static libraries, the only thing that changes our object files
// are included whole static libraries, so check to see if any of
// those have coverage enabled.
- ctx.VisitDirectDeps(func(m android.Module) {
- if ctx.OtherModuleDependencyTag(m) != wholeStaticDepTag {
- return
- }
-
+ ctx.VisitDirectDepsWithTag(wholeStaticDepTag, func(m android.Module) {
if cc, ok := m.(*Module); ok && cc.coverage != nil {
if cc.coverage.linkCoverage {
cov.linkCoverage = true
diff --git a/cc/util.go b/cc/util.go
index 7041029..5131b09 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -40,50 +40,11 @@
return android.JoinWithPrefix(names, "-l")
}
-func indexList(s string, list []string) int {
- for i, l := range list {
- if l == s {
- return i
- }
- }
-
- return -1
-}
-
-func inList(s string, list []string) bool {
- return indexList(s, list) != -1
-}
-
-func filterList(list []string, filter []string) (remainder []string, filtered []string) {
- for _, l := range list {
- if inList(l, filter) {
- filtered = append(filtered, l)
- } else {
- remainder = append(remainder, l)
- }
- }
-
- return
-}
-
-func removeListFromList(list []string, filter_out []string) (result []string) {
- result = make([]string, 0, len(list))
- for _, l := range list {
- if !inList(l, filter_out) {
- result = append(result, l)
- }
- }
- return
-}
-
-func removeFromList(s string, list []string) (bool, []string) {
- i := indexList(s, list)
- if i != -1 {
- return true, append(list[:i], list[i+1:]...)
- } else {
- return false, list
- }
-}
+var indexList = android.IndexList
+var inList = android.InList
+var filterList = android.FilterList
+var removeListFromList = android.RemoveListFromList
+var removeFromList = android.RemoveFromList
var libNameRegexp = regexp.MustCompile(`^lib(.*)$`)
diff --git a/finder/Android.bp b/finder/Android.bp
index b5c0e13..47b47c9 100644
--- a/finder/Android.bp
+++ b/finder/Android.bp
@@ -30,7 +30,7 @@
"finder_test.go",
],
deps: [
- "soong-fs",
+ "soong-finder-fs",
],
}
diff --git a/finder/cmd/finder.go b/finder/cmd/finder.go
index 70c1dc4..ab9108f 100644
--- a/finder/cmd/finder.go
+++ b/finder/cmd/finder.go
@@ -28,7 +28,7 @@
"time"
"android/soong/finder"
- "android/soong/fs"
+ "android/soong/finder/fs"
)
var (
diff --git a/finder/finder.go b/finder/finder.go
index 2dd8e0b..89be0f5 100644
--- a/finder/finder.go
+++ b/finder/finder.go
@@ -30,7 +30,7 @@
"sync/atomic"
"time"
- "android/soong/fs"
+ "android/soong/finder/fs"
)
// This file provides a Finder struct that can quickly search for files satisfying
@@ -1384,7 +1384,7 @@
f.onFsError(path, err)
// if listing the contents of the directory fails (presumably due to
// permission denied), then treat the directory as empty
- children = []os.FileInfo{}
+ children = nil
}
var subdirs []string
diff --git a/finder/finder_test.go b/finder/finder_test.go
index 1522c68..29711fc 100644
--- a/finder/finder_test.go
+++ b/finder/finder_test.go
@@ -21,12 +21,12 @@
"os"
"path/filepath"
"reflect"
+ "runtime/debug"
"sort"
"testing"
"time"
- "android/soong/fs"
- "runtime/debug"
+ "android/soong/finder/fs"
)
// some utils for tests to use
diff --git a/fs/Android.bp b/finder/fs/Android.bp
similarity index 85%
rename from fs/Android.bp
rename to finder/fs/Android.bp
index f4706ca..27e3c7d 100644
--- a/fs/Android.bp
+++ b/finder/fs/Android.bp
@@ -17,10 +17,14 @@
//
bootstrap_go_package {
- name: "soong-fs",
- pkgPath: "android/soong/fs",
+ name: "soong-finder-fs",
+ pkgPath: "android/soong/finder/fs",
srcs: [
"fs.go",
+ "readdir.go",
+ ],
+ testSrcs: [
+ "readdir_test.go",
],
darwin: {
srcs: [
diff --git a/fs/fs.go b/finder/fs/fs.go
similarity index 94%
rename from fs/fs.go
rename to finder/fs/fs.go
index eff8ad0..9c138cd 100644
--- a/fs/fs.go
+++ b/finder/fs/fs.go
@@ -51,7 +51,7 @@
// getting information about files
Open(name string) (file io.ReadCloser, err error)
Lstat(path string) (stats os.FileInfo, err error)
- ReadDir(path string) (contents []os.FileInfo, err error)
+ ReadDir(path string) (contents []DirEntryInfo, err error)
InodeNumber(info os.FileInfo) (number uint64, err error)
DeviceNumber(info os.FileInfo) (number uint64, err error)
@@ -67,18 +67,50 @@
ViewId() (id string) // Some unique id of the user accessing the filesystem
}
+// DentryInfo is a subset of the functionality available through os.FileInfo that might be able
+// to be gleaned through only a syscall.Getdents without requiring a syscall.Lstat of every file.
+type DirEntryInfo interface {
+ Name() string
+ Mode() os.FileMode // the file type encoded as an os.FileMode
+ IsDir() bool
+}
+
+type dirEntryInfo struct {
+ name string
+ mode os.FileMode
+ modeExists bool
+}
+
+var _ DirEntryInfo = os.FileInfo(nil)
+
+func (d *dirEntryInfo) Name() string { return d.name }
+func (d *dirEntryInfo) Mode() os.FileMode { return d.mode }
+func (d *dirEntryInfo) IsDir() bool { return d.mode.IsDir() }
+func (d *dirEntryInfo) String() string { return d.name + ": " + d.mode.String() }
+
// osFs implements FileSystem using the local disk.
type osFs struct{}
+var _ FileSystem = (*osFs)(nil)
+
func (osFs) Open(name string) (io.ReadCloser, error) { return os.Open(name) }
func (osFs) Lstat(path string) (stats os.FileInfo, err error) {
return os.Lstat(path)
}
-func (osFs) ReadDir(path string) (contents []os.FileInfo, err error) {
- return ioutil.ReadDir(path)
+func (osFs) ReadDir(path string) (contents []DirEntryInfo, err error) {
+ entries, err := readdir(path)
+ if err != nil {
+ return nil, err
+ }
+ for _, entry := range entries {
+ contents = append(contents, entry)
+ }
+
+ return contents, nil
}
+
func (osFs) Rename(oldPath string, newPath string) error {
return os.Rename(oldPath, newPath)
}
@@ -154,6 +186,8 @@
aggregatesLock sync.Mutex
}
+var _ FileSystem = (*MockFs)(nil)
+
type mockInode struct {
modTime time.Time
permTime time.Time
@@ -475,7 +509,7 @@
fmt.Errorf("%v is not a mockFileInfo", info)
}
-func (m *MockFs) ReadDir(path string) (contents []os.FileInfo, err error) {
+func (m *MockFs) ReadDir(path string) (contents []DirEntryInfo, err error) {
// update aggregates
m.aggregatesLock.Lock()
m.ReadDirCalls = append(m.ReadDirCalls, path)
@@ -486,7 +520,7 @@
if err != nil {
return nil, err
}
- results := []os.FileInfo{}
+ results := []DirEntryInfo{}
dir, err := m.getDir(path, false)
if err != nil {
return nil, err
diff --git a/fs/fs_darwin.go b/finder/fs/fs_darwin.go
similarity index 100%
rename from fs/fs_darwin.go
rename to finder/fs/fs_darwin.go
diff --git a/fs/fs_linux.go b/finder/fs/fs_linux.go
similarity index 100%
rename from fs/fs_linux.go
rename to finder/fs/fs_linux.go
diff --git a/finder/fs/readdir.go b/finder/fs/readdir.go
new file mode 100644
index 0000000..f6d7813
--- /dev/null
+++ b/finder/fs/readdir.go
@@ -0,0 +1,219 @@
+// Copyright 2017 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
+
+// This is based on the readdir implementation from Go 1.9:
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+import (
+ "os"
+ "syscall"
+ "unsafe"
+)
+
+const (
+ blockSize = 4096
+)
+
+func readdir(path string) ([]DirEntryInfo, error) {
+ f, err := os.Open(path)
+ defer f.Close()
+
+ if err != nil {
+ return nil, err
+ }
+ // This implicitly switches the fd to non-blocking mode, which is less efficient than what
+ // file.ReadDir does since it will keep a thread blocked and not just a goroutine.
+ fd := int(f.Fd())
+
+ buf := make([]byte, blockSize)
+ entries := make([]*dirEntryInfo, 0, 100)
+
+ for {
+ n, errno := syscall.ReadDirent(fd, buf)
+ if errno != nil {
+ err = os.NewSyscallError("readdirent", errno)
+ break
+ }
+ if n <= 0 {
+ break // EOF
+ }
+
+ entries = parseDirent(buf[:n], entries)
+ }
+
+ ret := make([]DirEntryInfo, 0, len(entries))
+
+ for _, entry := range entries {
+ if !entry.modeExists {
+ mode, lerr := lstatFileMode(path + "/" + entry.name)
+ if os.IsNotExist(lerr) {
+ // File disappeared between readdir + stat.
+ // Just treat it as if it didn't exist.
+ continue
+ }
+ if lerr != nil {
+ return ret, lerr
+ }
+ entry.mode = mode
+ entry.modeExists = true
+ }
+ ret = append(ret, entry)
+ }
+
+ return ret, err
+}
+
+func parseDirent(buf []byte, entries []*dirEntryInfo) []*dirEntryInfo {
+ for len(buf) > 0 {
+ reclen, ok := direntReclen(buf)
+ if !ok || reclen > uint64(len(buf)) {
+ return entries
+ }
+ rec := buf[:reclen]
+ buf = buf[reclen:]
+ ino, ok := direntIno(rec)
+ if !ok {
+ break
+ }
+ if ino == 0 { // File absent in directory.
+ continue
+ }
+ typ, ok := direntType(rec)
+ if !ok {
+ break
+ }
+ const namoff = uint64(unsafe.Offsetof(syscall.Dirent{}.Name))
+ namlen, ok := direntNamlen(rec)
+ if !ok || namoff+namlen > uint64(len(rec)) {
+ break
+ }
+ name := rec[namoff : namoff+namlen]
+
+ for i, c := range name {
+ if c == 0 {
+ name = name[:i]
+ break
+ }
+ }
+ // Check for useless names before allocating a string.
+ if string(name) == "." || string(name) == ".." {
+ continue
+ }
+
+ mode, modeExists := direntTypeToFileMode(typ)
+
+ entries = append(entries, &dirEntryInfo{string(name), mode, modeExists})
+ }
+ return entries
+}
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Ino), unsafe.Sizeof(syscall.Dirent{}.Ino))
+}
+
+func direntType(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Type), unsafe.Sizeof(syscall.Dirent{}.Type))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(syscall.Dirent{}.Reclen), unsafe.Sizeof(syscall.Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ reclen, ok := direntReclen(buf)
+ if !ok {
+ return 0, false
+ }
+ return reclen - uint64(unsafe.Offsetof(syscall.Dirent{}.Name)), true
+}
+
+// readInt returns the size-bytes unsigned integer in native byte order at offset off.
+func readInt(b []byte, off, size uintptr) (u uint64, ok bool) {
+ if len(b) < int(off+size) {
+ return 0, false
+ }
+ return readIntLE(b[off:], size), true
+}
+
+func readIntLE(b []byte, size uintptr) uint64 {
+ switch size {
+ case 1:
+ return uint64(b[0])
+ case 2:
+ _ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8
+ case 4:
+ _ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24
+ case 8:
+ _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
+ return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
+ uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
+ default:
+ panic("syscall: readInt with unsupported size")
+ }
+}
+
+// If the directory entry doesn't specify the type, fall back to using lstat to get the type.
+func lstatFileMode(name string) (os.FileMode, error) {
+ stat, err := os.Lstat(name)
+ if err != nil {
+ return 0, err
+ }
+
+ return stat.Mode() & (os.ModeType | os.ModeCharDevice), nil
+}
+
+// from Linux and Darwin dirent.h
+const (
+ DT_UNKNOWN = 0
+ DT_FIFO = 1
+ DT_CHR = 2
+ DT_DIR = 4
+ DT_BLK = 6
+ DT_REG = 8
+ DT_LNK = 10
+ DT_SOCK = 12
+)
+
+func direntTypeToFileMode(typ uint64) (os.FileMode, bool) {
+ exists := true
+ var mode os.FileMode
+ switch typ {
+ case DT_UNKNOWN:
+ exists = false
+ case DT_FIFO:
+ mode = os.ModeNamedPipe
+ case DT_CHR:
+ mode = os.ModeDevice | os.ModeCharDevice
+ case DT_DIR:
+ mode = os.ModeDir
+ case DT_BLK:
+ mode = os.ModeDevice
+ case DT_REG:
+ mode = 0
+ case DT_LNK:
+ mode = os.ModeSymlink
+ case DT_SOCK:
+ mode = os.ModeSocket
+ default:
+ exists = false
+ }
+
+ return mode, exists
+}
diff --git a/finder/fs/readdir_test.go b/finder/fs/readdir_test.go
new file mode 100644
index 0000000..24a6d18
--- /dev/null
+++ b/finder/fs/readdir_test.go
@@ -0,0 +1,312 @@
+// Copyright 2017 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"
+ "reflect"
+ "runtime"
+ "testing"
+)
+
+func TestParseDirent(t *testing.T) {
+ testCases := []struct {
+ name string
+ in []byte
+ out []*dirEntryInfo
+ }{
+ {
+ // Test that type DT_DIR is translated to os.ModeDir
+ name: "dir",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x28, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ out: []*dirEntryInfo{
+ {".module_paths", os.ModeDir, true},
+ },
+ },
+ {
+ // Test that type DT_REG is translated to a regular file
+ name: "file",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x28, 0x00,
+ // unsigned char d_type;
+ 0x08,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ out: []*dirEntryInfo{
+ {".module_paths", 0, true},
+ },
+ },
+ {
+ // Test that type DT_LNK is translated to a regular os.ModeSymlink
+ name: "symlink",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x28, 0x00,
+ // unsigned char d_type;
+ 0x0a,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ out: []*dirEntryInfo{
+ {".module_paths", os.ModeSymlink, true},
+ },
+ },
+ {
+ // Test that type DT_UNKNOWN sets modeExists: false
+ name: "unknown",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x28, 0x00,
+ // unsigned char d_type;
+ 0x00,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ out: []*dirEntryInfo{
+ {".module_paths", 0, false},
+ },
+ },
+ {
+ // Test a name with no padding after the null terminator
+ name: "no padding",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x20, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
+ },
+ out: []*dirEntryInfo{
+ {".module_path", os.ModeDir, true},
+ },
+ },
+ {
+ // Test two sequential entries
+ name: "two entries",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x28, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x28, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x74,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ out: []*dirEntryInfo{
+ {".module_paths", os.ModeDir, true},
+ {".module_patht", os.ModeDir, true},
+ },
+ },
+ {
+ // Test two sequential entries with no padding between them
+ name: "two entries no padding",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x20, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
+
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x28, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ out: []*dirEntryInfo{
+ {".module_path", os.ModeDir, true},
+ {".module_paths", os.ModeDir, true},
+ },
+ },
+ {
+ // Test an empty buffer. This shouldn't happen in practice because
+ // readdir doesn't call parseDirent if no bytes were returned.
+ name: "empty",
+ in: []byte{},
+ out: nil,
+ },
+ {
+ name: "missing null terminator",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x20, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+ },
+ out: []*dirEntryInfo{
+ {".module_paths", os.ModeDir, true},
+ },
+ },
+ {
+ // Test two sequential entries where the first has an incorrect d_reclen.
+ // Should return with no entries.
+ name: "two entries first malformed",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x10, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
+
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x28, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ out: nil,
+ },
+ {
+ // Test two sequential entries where the second has an incorrect d_reclen.
+ // Should return the first entry.
+ name: "two entries second malformed",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x28, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
+
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x10, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x73,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ },
+ out: []*dirEntryInfo{
+ {".module_path", os.ModeDir, true},
+ },
+ },
+ {
+ // Test a reclen that goes past the end of the buffer.
+ name: "overrun",
+ in: []byte{
+ // __ino64_t d_ino;
+ 0xfb, 0x10, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00,
+ // __off64_t d_off;
+ 0xeb, 0x85, 0x20, 0x91, 0xb9, 0x14, 0x34, 0x03,
+ // unsigned short int d_reclen;
+ 0x30, 0x00,
+ // unsigned char d_type;
+ 0x04,
+ // char d_name[];
+ 0x2e, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x00,
+ },
+ out: nil,
+ },
+ }
+
+ if runtime.GOOS != "linux" {
+ t.Skip("depends on Linux definitions of syscall.Dirent")
+ }
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ entries := parseDirent(testCase.in, nil)
+ if !reflect.DeepEqual(testCase.out, entries) {
+ t.Fatalf("expected:\n %v\ngot:\n %v\n", testCase.out, entries)
+ }
+ })
+ }
+}
diff --git a/java/java.go b/java/java.go
index dbf202a..8159af8 100644
--- a/java/java.go
+++ b/java/java.go
@@ -597,6 +597,29 @@
// classpath
flags.bootClasspath.AddPaths(deps.bootClasspath)
flags.classpath.AddPaths(deps.classpath)
+
+ if len(flags.bootClasspath) == 0 && ctx.Host() && !ctx.Config().TargetOpenJDK9() &&
+ !Bool(j.properties.No_standard_libs) &&
+ inList(flags.javaVersion, []string{"1.6", "1.7", "1.8"}) {
+ // Give host-side tools a version of OpenJDK's standard libraries
+ // close to what they're targeting. As of Dec 2017, AOSP is only
+ // bundling OpenJDK 8 and 9, so nothing < 8 is available.
+ //
+ // When building with OpenJDK 8, the following should have no
+ // effect since those jars would be available by default.
+ //
+ // When building with OpenJDK 9 but targeting a version < 1.8,
+ // putting them on the bootclasspath means that:
+ // a) code can't (accidentally) refer to OpenJDK 9 specific APIs
+ // b) references to existing APIs are not reinterpreted in an
+ // OpenJDK 9-specific way, eg. calls to subclasses of
+ // java.nio.Buffer as in http://b/70862583
+ java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
+ flags.bootClasspath = append(flags.bootClasspath,
+ android.PathForSource(ctx, java8Home, "jre/lib/jce.jar"),
+ android.PathForSource(ctx, java8Home, "jre/lib/rt.jar"))
+ }
+
// systemModules
if deps.systemModules != nil {
flags.systemModules = append(flags.systemModules, deps.systemModules)
diff --git a/java/java_test.go b/java/java_test.go
index 84fe903..6e14a70 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -53,6 +53,12 @@
}
func testConfig(env map[string]string) android.Config {
+ if env == nil {
+ env = make(map[string]string)
+ }
+ if env["ANDROID_JAVA8_HOME"] == "" {
+ env["ANDROID_JAVA8_HOME"] = "jdk8"
+ }
return android.TestArchConfig(buildDir, env)
}
@@ -150,6 +156,9 @@
"build/target/product/security/testkey": nil,
"build/soong/scripts/jar-wrapper.sh": nil,
+
+ "jdk8/jre/lib/jce.jar": nil,
+ "jdk8/jre/lib/rt.jar": nil,
}
for k, v := range fs {
@@ -364,11 +373,12 @@
},
{
- name: "host default",
- moduleType: "java_library_host",
- properties: ``,
- host: android.Host,
- classpath: []string{},
+ name: "host default",
+ moduleType: "java_library_host",
+ properties: ``,
+ host: android.Host,
+ bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
+ classpath: []string{},
},
{
name: "host nostdlib",
@@ -379,10 +389,11 @@
},
{
- name: "host supported default",
- host: android.Host,
- properties: `host_supported: true,`,
- classpath: []string{},
+ name: "host supported default",
+ host: android.Host,
+ properties: `host_supported: true,`,
+ classpath: []string{},
+ bootclasspath: []string{"jdk8/jre/lib/jce.jar", "jdk8/jre/lib/rt.jar"},
},
{
name: "host supported nostdlib",
diff --git a/java/system_modules.go b/java/system_modules.go
index 5234d17..196d041 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -112,11 +112,9 @@
func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) {
var jars android.Paths
- ctx.VisitDirectDeps(func(module android.Module) {
- if ctx.OtherModuleDependencyTag(module) == libTag {
- dep, _ := module.(Dependency)
- jars = append(jars, dep.HeaderJars()...)
- }
+ ctx.VisitDirectDepsWithTag(libTag, func(module android.Module) {
+ dep, _ := module.(Dependency)
+ jars = append(jars, dep.HeaderJars()...)
})
jars = append(jars, android.PathsForModuleSrc(ctx, system.properties.Jars)...)
diff --git a/python/binary.go b/python/binary.go
index 457c7fa..0314edb 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -133,10 +133,7 @@
var launcher_path android.Path
if embedded_launcher {
- ctx.VisitDirectDeps(func(m android.Module) {
- if ctx.OtherModuleDependencyTag(m) != launcherTag {
- return
- }
+ ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) {
if provider, ok := m.(IntermPathProvider); ok {
if launcher_path != nil {
panic(fmt.Errorf("launcher path was found before: %q",
diff --git a/ui/build/finder.go b/ui/build/finder.go
index a0f5d08..3bd6d87 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -16,7 +16,7 @@
import (
"android/soong/finder"
- "android/soong/fs"
+ "android/soong/finder/fs"
"android/soong/ui/logger"
"bytes"
"io/ioutil"