Merge changes from topic "hiddenapi"
* changes:
Move hiddenapi singleton rules to Soong
Add MissingDeps to RuleBuilder
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index e180342..33647d7 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -25,6 +25,7 @@
func init() {
RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
+ RegisterModuleType("prebuilt_etc_host", prebuiltEtcHostFactory)
PreDepsMutators(func(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
@@ -149,6 +150,9 @@
fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", *p.commonProperties.Owner)
}
fmt.Fprintln(w, "LOCAL_MODULE_TAGS := optional")
+ if p.Host() {
+ fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
+ }
fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", p.outputFilePath.String())
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", "$(OUT_DIR)/"+p.installDirPath.RelPathString())
fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", p.outputFilePath.Base())
@@ -178,6 +182,14 @@
return module
}
+func prebuiltEtcHostFactory() Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module)
+ // This module is host-only
+ InitAndroidArchModule(module, HostSupported, MultilibCommon)
+ return module
+}
+
const (
// coreMode is the variant for modules to be installed to system.
coreMode = "core"
@@ -190,7 +202,7 @@
// system or recovery.
func prebuiltEtcMutator(mctx BottomUpMutatorContext) {
m, ok := mctx.Module().(*PrebuiltEtc)
- if !ok {
+ if !ok || m.Host() {
return
}
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index d1a80af..f31fc9e 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -28,6 +28,7 @@
defer tearDown(buildDir)
ctx := NewTestArchContext()
ctx.RegisterModuleType("prebuilt_etc", ModuleFactoryAdaptor(PrebuiltEtcFactory))
+ ctx.RegisterModuleType("prebuilt_etc_host", ModuleFactoryAdaptor(prebuiltEtcHostFactory))
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
})
@@ -177,3 +178,18 @@
}
}
}
+
+func TestPrebuiltEtcHost(t *testing.T) {
+ ctx := testPrebuiltEtc(t, `
+ prebuilt_etc_host {
+ name: "foo.conf",
+ src: "foo.conf",
+ }
+ `)
+
+ buildOS := BuildOs.String()
+ p := ctx.ModuleForTests("foo.conf", buildOS+"_common").Module().(*PrebuiltEtc)
+ if !p.Host() {
+ t.Errorf("host bit is not set for a prebuilt_etc_host module.")
+ }
+}
diff --git a/cc/cc.go b/cc/cc.go
index 02f36d5..c09a2f3 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1378,6 +1378,7 @@
// NDK code linking to platform code is never okay.
ctx.ModuleErrorf("depends on non-NDK-built library %q",
ctx.OtherModuleName(to))
+ return
}
// At this point we know we have two NDK libraries, but we need to
diff --git a/scripts/build_broken_logs.go b/scripts/build_broken_logs.go
new file mode 100644
index 0000000..73832a6
--- /dev/null
+++ b/scripts/build_broken_logs.go
@@ -0,0 +1,266 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// This is a script that can be used to analyze the results from
+// build/soong/build_test.bash and recommend what devices need changes to their
+// BUILD_BROKEN_* flags.
+//
+// To use, download the logs.zip from one or more branches, and extract them
+// into subdirectories of the current directory. So for example, I have:
+//
+// ./aosp-master/aosp_arm/std_full.log
+// ./aosp-master/aosp_arm64/std_full.log
+// ./aosp-master/...
+// ./internal-master/aosp_arm/std_full.log
+// ./internal-master/aosp_arm64/std_full.log
+// ./internal-master/...
+//
+// Then I use `go run path/to/build_broken_logs.go *`
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+)
+
+func main() {
+ for _, branch := range os.Args[1:] {
+ fmt.Printf("\nBranch %s:\n", branch)
+ PrintResults(ParseBranch(branch))
+ }
+}
+
+type BuildBrokenBehavior int
+
+const (
+ DefaultFalse BuildBrokenBehavior = iota
+ DefaultTrue
+ DefaultDeprecated
+)
+
+var buildBrokenSettings = []struct {
+ name string
+ behavior BuildBrokenBehavior
+ warnings []string
+}{
+ {
+ name: "BUILD_BROKEN_DUP_COPY_HEADERS",
+ behavior: DefaultDeprecated,
+ warnings: []string{"Duplicate header copy:"},
+ },
+ {
+ name: "BUILD_BROKEN_DUP_RULES",
+ behavior: DefaultFalse,
+ warnings: []string{"overriding commands for target"},
+ },
+ {
+ name: "BUILD_BROKEN_ANDROIDMK_EXPORTS",
+ behavior: DefaultFalse,
+ warnings: []string{"export_keyword"},
+ },
+ {
+ name: "BUILD_BROKEN_PHONY_TARGETS",
+ behavior: DefaultFalse,
+ warnings: []string{
+ "depends on PHONY target",
+ "looks like a real file",
+ "writing to readonly directory",
+ },
+ },
+ {
+ name: "BUILD_BROKEN_ENG_DEBUG_TAGS",
+ behavior: DefaultTrue,
+ warnings: []string{
+ "Changes.md#LOCAL_MODULE_TAGS",
+ },
+ },
+}
+
+type ProductBranch struct {
+ Branch string
+ Name string
+}
+
+type ProductLog struct {
+ ProductBranch
+ Log
+ Device string
+}
+
+type Log struct {
+ BuildBroken []*bool
+ HasBroken []bool
+}
+
+func Merge(l, l2 Log) Log {
+ if len(l.BuildBroken) == 0 {
+ l.BuildBroken = make([]*bool, len(buildBrokenSettings))
+ }
+ if len(l.HasBroken) == 0 {
+ l.HasBroken = make([]bool, len(buildBrokenSettings))
+ }
+
+ if len(l.BuildBroken) != len(l2.BuildBroken) || len(l.HasBroken) != len(l2.HasBroken) {
+ panic("mis-matched logs")
+ }
+
+ for i, v := range l.BuildBroken {
+ if v == nil {
+ l.BuildBroken[i] = l2.BuildBroken[i]
+ }
+ }
+ for i := range l.HasBroken {
+ l.HasBroken[i] = l.HasBroken[i] || l2.HasBroken[i]
+ }
+
+ return l
+}
+
+func PrintResults(products []ProductLog) {
+ devices := map[string]Log{}
+ deviceNames := []string{}
+
+ for _, product := range products {
+ device := product.Device
+ if _, ok := devices[device]; !ok {
+ deviceNames = append(deviceNames, device)
+ }
+ devices[device] = Merge(devices[device], product.Log)
+ }
+
+ sort.Strings(deviceNames)
+
+ for i, setting := range buildBrokenSettings {
+ printed := false
+
+ for _, device := range deviceNames {
+ log := devices[device]
+
+ if setting.behavior == DefaultTrue {
+ if log.BuildBroken[i] == nil || *log.BuildBroken[i] == false {
+ if log.HasBroken[i] {
+ printed = true
+ fmt.Printf(" %s needs to set %s := true\n", device, setting.name)
+ }
+ } else if !log.HasBroken[i] {
+ printed = true
+ fmt.Printf(" %s sets %s := true, but does not need it\n", device, setting.name)
+ }
+ } else if setting.behavior == DefaultFalse {
+ if log.BuildBroken[i] == nil {
+ // Nothing to be done
+ } else if *log.BuildBroken[i] == false {
+ printed = true
+ fmt.Printf(" %s sets %s := false, which is the default and can be removed\n", device, setting.name)
+ } else if !log.HasBroken[i] {
+ printed = true
+ fmt.Printf(" %s sets %s := true, but does not need it\n", device, setting.name)
+ }
+ } else if setting.behavior == DefaultDeprecated {
+ if log.BuildBroken[i] != nil {
+ printed = true
+ if log.HasBroken[i] {
+ fmt.Printf(" %s sets %s := %v, which is deprecated, but has failures\n", device, setting.name, *log.BuildBroken[i])
+ } else {
+ fmt.Printf(" %s sets %s := %v, which is deprecated and can be removed\n", device, setting.name, *log.BuildBroken[i])
+ }
+ }
+ }
+ }
+
+ if printed {
+ fmt.Println()
+ }
+ }
+}
+
+func ParseBranch(name string) []ProductLog {
+ products, err := filepath.Glob(filepath.Join(name, "*"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ret := []ProductLog{}
+ for _, product := range products {
+ product = filepath.Base(product)
+
+ ret = append(ret, ParseProduct(ProductBranch{Branch: name, Name: product}))
+ }
+ return ret
+}
+
+func ParseProduct(p ProductBranch) ProductLog {
+ soongLog, err := ioutil.ReadFile(filepath.Join(p.Branch, p.Name, "soong.log"))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ ret := ProductLog{
+ ProductBranch: p,
+ Log: Log{
+ BuildBroken: make([]*bool, len(buildBrokenSettings)),
+ HasBroken: make([]bool, len(buildBrokenSettings)),
+ },
+ }
+
+ lines := strings.Split(string(soongLog), "\n")
+ for _, line := range lines {
+ fields := strings.Split(line, " ")
+ if len(fields) != 5 {
+ continue
+ }
+
+ if fields[3] == "TARGET_DEVICE" {
+ ret.Device = fields[4]
+ }
+
+ if strings.HasPrefix(fields[3], "BUILD_BROKEN_") {
+ for i, setting := range buildBrokenSettings {
+ if setting.name == fields[3] {
+ ret.BuildBroken[i] = ParseBoolPtr(fields[4])
+ }
+ }
+ }
+ }
+
+ stdLog, err := ioutil.ReadFile(filepath.Join(p.Branch, p.Name, "std_full.log"))
+ if err != nil {
+ log.Fatal(err)
+ }
+ stdStr := string(stdLog)
+
+ for i, setting := range buildBrokenSettings {
+ for _, warning := range setting.warnings {
+ if strings.Contains(stdStr, warning) {
+ ret.HasBroken[i] = true
+ }
+ }
+ }
+
+ return ret
+}
+
+func ParseBoolPtr(str string) *bool {
+ var ret *bool
+ if str != "" {
+ b := str == "true"
+ ret = &b
+ }
+ return ret
+}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 1ab855d..98bb1c5 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -206,6 +206,7 @@
// Not used, but useful to be in the soong.log
"BUILD_BROKEN_ANDROIDMK_EXPORTS",
"BUILD_BROKEN_DUP_COPY_HEADERS",
+ "BUILD_BROKEN_ENG_DEBUG_TAGS",
}, exportEnvVars...), BannerVars...)
make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true)