Merge "Add common BPF helper to include path"
diff --git a/Android.bp b/Android.bp
index a70f73c..b407314 100644
--- a/Android.bp
+++ b/Android.bp
@@ -61,6 +61,7 @@
"android/prebuilt_etc.go",
"android/proto.go",
"android/register.go",
+ "android/rule_builder.go",
"android/sh_binary.go",
"android/singleton.go",
"android/testing.go",
@@ -77,9 +78,11 @@
"android/expand_test.go",
"android/namespace_test.go",
"android/neverallow_test.go",
+ "android/onceper_test.go",
"android/paths_test.go",
"android/prebuilt_test.go",
"android/prebuilt_etc_test.go",
+ "android/rule_builder_test.go",
"android/util_test.go",
"android/variable_test.go",
],
@@ -145,6 +148,7 @@
"cc/sabi.go",
"cc/stl.go",
"cc/strip.go",
+ "cc/sysprop.go",
"cc/tidy.go",
"cc/util.go",
"cc/vndk.go",
@@ -175,6 +179,8 @@
"cc/genrule.go",
"cc/vendor_public_library.go",
+
+ "cc/testing.go",
],
testSrcs: [
"cc/cc_test.go",
@@ -248,6 +254,7 @@
"java/gen.go",
"java/genrule.go",
"java/hiddenapi.go",
+ "java/hiddenapi_singleton.go",
"java/jacoco.go",
"java/java.go",
"java/jdeps.go",
@@ -374,6 +381,25 @@
pluginFor: ["soong_build"],
}
+bootstrap_go_package {
+ name: "soong-sysprop",
+ pkgPath: "android/soong/sysprop",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ "soong-cc",
+ "soong-java",
+ ],
+ srcs: [
+ "sysprop/sysprop_library.go",
+ ],
+ testSrcs: [
+ "sysprop/sysprop_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
+
//
// Defaults to enable various configurations of host bionic
//
diff --git a/README.md b/README.md
index 74d49bb..44a98f3 100644
--- a/README.md
+++ b/README.md
@@ -34,7 +34,7 @@
all Android.bp files.
For a list of valid module types and their properties see
-[$OUT_DIR/soong/.bootstrap/docs/soong_build.html](http://go/Android.bp).
+[$OUT_DIR/soong/docs/soong_build.html](http://go/Android.bp).
### Globs
diff --git a/android/apex.go b/android/apex.go
index a93baf6..bf11ba2 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -139,6 +139,7 @@
var apexData OncePer
var apexNamesMapMutex sync.Mutex
+var apexNamesKey = NewOnceKey("apexNames")
// This structure maintains the global mapping in between modules and APEXes.
// Examples:
@@ -147,7 +148,7 @@
// apexNamesMap()["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar
// apexNamesMap()["foo"]["bar"] doesn't exist: foo is not built for APEX bar
func apexNamesMap() map[string]map[string]bool {
- return apexData.Once("apexNames", func() interface{} {
+ return apexData.Once(apexNamesKey, func() interface{} {
return make(map[string]map[string]bool)
}).(map[string]map[string]bool)
}
diff --git a/android/api_levels.go b/android/api_levels.go
index 1b56625..51d4703 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -51,8 +51,10 @@
return PathForOutput(ctx, "api_levels.json")
}
+var apiLevelsMapKey = NewOnceKey("ApiLevelsMap")
+
func getApiLevelsMap(config Config) map[string]int {
- return config.Once("ApiLevelsMap", func() interface{} {
+ return config.Once(apiLevelsMapKey, func() interface{} {
baseApiLevel := 9000
apiLevelsMap := map[string]int{
"G": 9,
diff --git a/android/arch.go b/android/arch.go
index 6aeccb0..b88b275 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -15,9 +15,11 @@
package android
import (
+ "encoding"
"fmt"
"reflect"
"runtime"
+ "strconv"
"strings"
"github.com/google/blueprint/proptools"
@@ -369,6 +371,23 @@
return a.Name
}
+var _ encoding.TextMarshaler = ArchType{}
+
+func (a ArchType) MarshalText() ([]byte, error) {
+ return []byte(strconv.Quote(a.String())), nil
+}
+
+var _ encoding.TextUnmarshaler = &ArchType{}
+
+func (a *ArchType) UnmarshalText(text []byte) error {
+ if u, ok := archTypeMap[string(text)]; ok {
+ *a = u
+ return nil
+ }
+
+ return fmt.Errorf("unknown ArchType %q", text)
+}
+
var BuildOs = func() OsType {
switch runtime.GOOS {
case "linux":
@@ -879,7 +898,7 @@
propertiesValue.Interface()))
}
- archPropTypes := archPropTypeMap.Once(t, func() interface{} {
+ archPropTypes := archPropTypeMap.Once(NewCustomOnceKey(t), func() interface{} {
return createArchType(t)
}).([]reflect.Type)
@@ -1169,7 +1188,7 @@
targets := make(map[OsType][]Target)
var targetErr error
- addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi *[]string) {
+ addTarget := func(os OsType, archName string, archVariant, cpuVariant *string, abi []string) {
if targetErr != nil {
return
}
@@ -1358,7 +1377,7 @@
for _, config := range archConfigs {
arch, err := decodeArch(os, config.arch, &config.archVariant,
- &config.cpuVariant, &config.abi)
+ &config.cpuVariant, config.abi)
if err != nil {
return nil, err
}
@@ -1373,7 +1392,7 @@
}
// Convert a set of strings from product variables into a single Arch struct
-func decodeArch(os OsType, arch string, archVariant, cpuVariant *string, abi *[]string) (Arch, error) {
+func decodeArch(os OsType, arch string, archVariant, cpuVariant *string, abi []string) (Arch, error) {
stringPtr := func(p *string) string {
if p != nil {
return *p
@@ -1381,13 +1400,6 @@
return ""
}
- slicePtr := func(p *[]string) []string {
- if p != nil {
- return *p
- }
- return nil
- }
-
archType, ok := archTypeMap[arch]
if !ok {
return Arch{}, fmt.Errorf("unknown arch %q", arch)
@@ -1397,7 +1409,7 @@
ArchType: archType,
ArchVariant: stringPtr(archVariant),
CpuVariant: stringPtr(cpuVariant),
- Abi: slicePtr(abi),
+ Abi: abi,
Native: true,
}
diff --git a/android/config.go b/android/config.go
index 122b99b..63788b7 100644
--- a/android/config.go
+++ b/android/config.go
@@ -202,10 +202,10 @@
productVariables: productVariables{
DeviceName: stringPtr("test_device"),
Platform_sdk_version: intPtr(26),
- AAPTConfig: &[]string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
+ AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
AAPTPreferredConfig: stringPtr("xhdpi"),
AAPTCharacteristics: stringPtr("nosdcard"),
- AAPTPrebuiltDPI: &[]string{"xhdpi", "xxhdpi"},
+ AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"},
},
buildDir: buildDir,
@@ -476,10 +476,7 @@
}
func (c *config) ResourceOverlays() []string {
- if c.productVariables.ResourceOverlays == nil {
- return nil
- }
- return *c.productVariables.ResourceOverlays
+ return c.productVariables.ResourceOverlays
}
func (c *config) PlatformVersionName() string {
@@ -544,7 +541,7 @@
}
func (c *config) ProductAAPTConfig() []string {
- return stringSlice(c.productVariables.AAPTConfig)
+ return c.productVariables.AAPTConfig
}
func (c *config) ProductAAPTPreferredConfig() string {
@@ -556,7 +553,7 @@
}
func (c *config) ProductAAPTPrebuiltDPI() []string {
- return stringSlice(c.productVariables.AAPTPrebuiltDPI)
+ return c.productVariables.AAPTPrebuiltDPI
}
func (c *config) DefaultAppCertificateDir(ctx PathContext) SourcePath {
@@ -668,6 +665,10 @@
}
}
+func (c *config) DisableScudo() bool {
+ return Bool(c.productVariables.DisableScudo)
+}
+
func (c *config) EnableXOM() bool {
if c.productVariables.EnableXOM == nil {
return true
@@ -734,10 +735,10 @@
func (c *config) EnforceRROForModule(name string) bool {
enforceList := c.productVariables.EnforceRROTargets
if enforceList != nil {
- if len(*enforceList) == 1 && (*enforceList)[0] == "*" {
+ if len(enforceList) == 1 && (enforceList)[0] == "*" {
return true
}
- return InList(name, *enforceList)
+ return InList(name, enforceList)
}
return false
}
@@ -745,7 +746,7 @@
func (c *config) EnforceRROExcludedOverlay(path string) bool {
excluded := c.productVariables.EnforceRROExcludedOverlays
if excluded != nil {
- for _, exclude := range *excluded {
+ for _, exclude := range excluded {
if strings.HasPrefix(path, exclude) {
return true
}
@@ -830,10 +831,7 @@
}
func (c *deviceConfig) SystemSdkVersions() []string {
- if c.config.productVariables.DeviceSystemSdkVersions == nil {
- return nil
- }
- return *c.config.productVariables.DeviceSystemSdkVersions
+ return c.config.productVariables.DeviceSystemSdkVersions
}
func (c *deviceConfig) PlatformSystemSdkVersions() []string {
@@ -876,12 +874,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
}
}
@@ -962,28 +960,28 @@
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 (c *config) XOMDisabledForPath(path string) bool {
if c.productVariables.XOMExcludePaths == nil {
return false
}
- return PrefixInList(path, *c.productVariables.XOMExcludePaths)
+ return PrefixInList(path, c.productVariables.XOMExcludePaths)
}
func (c *config) VendorConfig(name string) VendorConfig {
@@ -1024,22 +1022,14 @@
return c.productVariables.EnforceSystemCertificateWhitelist
}
-func (c *config) HiddenAPIStubFlags() string {
- return String(c.productVariables.HiddenAPIStubFlags)
+func (c *config) ProductHiddenAPIStubs() []string {
+ return c.productVariables.ProductHiddenAPIStubs
}
-func (c *config) HiddenAPIFlags() string {
- return String(c.productVariables.HiddenAPIFlags)
+func (c *config) ProductHiddenAPIStubsSystem() []string {
+ return c.productVariables.ProductHiddenAPIStubsSystem
}
-func (c *config) HiddenAPIExtraAppUsageJars() []string {
- return c.productVariables.HiddenAPIExtraAppUsageJars
-}
-
-func stringSlice(s *[]string) []string {
- if s != nil {
- return *s
- } else {
- return nil
- }
+func (c *config) ProductHiddenAPIStubsTest() []string {
+ return c.productVariables.ProductHiddenAPIStubsTest
}
diff --git a/android/hooks.go b/android/hooks.go
index 57560d2..6b2468d 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -123,7 +123,7 @@
install []func(InstallHookContext)
}
-func loadHookMutator(ctx TopDownMutatorContext) {
+func LoadHookMutator(ctx TopDownMutatorContext) {
if m, ok := ctx.Module().(Module); ok {
// Cast through *androidTopDownMutatorContext because AppendProperties is implemented
// on *androidTopDownMutatorContext but not exposed through TopDownMutatorContext
diff --git a/android/makevars.go b/android/makevars.go
index 3a7ec6e..2c2fb6f 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -22,6 +22,8 @@
"strconv"
"strings"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
)
@@ -38,7 +40,21 @@
type MakeVarsContext interface {
Config() Config
DeviceConfig() DeviceConfig
- SingletonContext() SingletonContext
+ AddNinjaFileDeps(deps ...string)
+ Fs() pathtools.FileSystem
+
+ ModuleName(module blueprint.Module) string
+ ModuleDir(module blueprint.Module) string
+ ModuleSubDir(module blueprint.Module) string
+ ModuleType(module blueprint.Module) string
+ BlueprintFile(module blueprint.Module) string
+
+ ModuleErrorf(module blueprint.Module, format string, args ...interface{})
+ Errorf(format string, args ...interface{})
+ Failed() bool
+
+ VisitAllModules(visit func(Module))
+ VisitAllModulesIf(pred func(Module) bool, visit func(Module))
// Verify the make variable matches the Soong version, fail the build
// if it does not. If the make variable is empty, just set it.
@@ -66,6 +82,8 @@
CheckRaw(name, value string)
}
+var _ PathContext = MakeVarsContext(nil)
+
type MakeVarsProvider func(ctx MakeVarsContext)
func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
@@ -74,10 +92,6 @@
///////////////////////////////////////////////////////////////////////////////
-func init() {
- RegisterSingletonType("makevars", makeVarsSingletonFunc)
-}
-
func makeVarsSingletonFunc() Singleton {
return &makeVarsSingleton{}
}
@@ -92,8 +106,8 @@
var makeVarsProviders []makeVarsProvider
type makeVarsContext struct {
+ SingletonContext
config Config
- ctx SingletonContext
pctx PackageContext
vars []makeVarsVariable
}
@@ -121,9 +135,8 @@
vars := []makeVarsVariable{}
for _, provider := range makeVarsProviders {
mctx := &makeVarsContext{
- config: ctx.Config(),
- ctx: ctx,
- pctx: provider.pctx,
+ SingletonContext: ctx,
+ pctx: provider.pctx,
}
provider.call(mctx)
@@ -229,22 +242,14 @@
return buf.Bytes()
}
-func (c *makeVarsContext) Config() Config {
- return c.config
-}
-
func (c *makeVarsContext) DeviceConfig() DeviceConfig {
- return DeviceConfig{c.config.deviceConfig}
-}
-
-func (c *makeVarsContext) SingletonContext() SingletonContext {
- return c.ctx
+ return DeviceConfig{c.Config().deviceConfig}
}
var ninjaDescaper = strings.NewReplacer("$$", "$")
func (c *makeVarsContext) Eval(ninjaStr string) (string, error) {
- s, err := c.ctx.Eval(c.pctx, ninjaStr)
+ s, err := c.SingletonContext.Eval(c.pctx, ninjaStr)
if err != nil {
return "", err
}
@@ -265,7 +270,7 @@
func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) {
value, err := c.Eval(ninjaStr)
if err != nil {
- c.ctx.Errorf(err.Error())
+ c.SingletonContext.Errorf(err.Error())
}
c.addVariableRaw(name, value, strict, sort)
}
diff --git a/android/module.go b/android/module.go
index 551824d..f2f1af1 100644
--- a/android/module.go
+++ b/android/module.go
@@ -481,6 +481,8 @@
prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool
}
+func (a *ModuleBase) DepsMutator(BottomUpMutatorContext) {}
+
func (a *ModuleBase) AddProperties(props ...interface{}) {
a.registerProps = append(a.registerProps, props...)
}
diff --git a/android/mutator.go b/android/mutator.go
index b77c2f0..e5f742f 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -74,7 +74,7 @@
var preArch = []RegisterMutatorFunc{
func(ctx RegisterMutatorsContext) {
- ctx.TopDown("load_hooks", loadHookMutator).Parallel()
+ ctx.TopDown("load_hooks", LoadHookMutator).Parallel()
},
RegisterNamespaceMutator,
RegisterPrebuiltsPreArchMutators,
diff --git a/android/namespace.go b/android/namespace.go
index b027ceb..dca2b8c 100644
--- a/android/namespace.go
+++ b/android/namespace.go
@@ -366,9 +366,6 @@
}
}
-func (n *NamespaceModule) DepsMutator(context BottomUpMutatorContext) {
-}
-
func (n *NamespaceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
}
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 9e4886c..8d53087 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -222,9 +222,6 @@
return m
}
-func (p *mockCcLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
-}
-
func (p *mockCcLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
@@ -244,8 +241,5 @@
return m
}
-func (p *mockJavaLibraryModule) DepsMutator(ctx BottomUpMutatorContext) {
-}
-
func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
diff --git a/android/onceper.go b/android/onceper.go
index f19f75c..f06f428 100644
--- a/android/onceper.go
+++ b/android/onceper.go
@@ -20,37 +20,51 @@
)
type OncePer struct {
- values sync.Map
- valuesLock sync.Mutex
+ values sync.Map
}
-type valueMap map[interface{}]interface{}
+type onceValueWaiter chan bool
+
+func (once *OncePer) maybeWaitFor(key OnceKey, value interface{}) interface{} {
+ if wait, isWaiter := value.(onceValueWaiter); isWaiter {
+ // The entry in the map is a placeholder waiter because something else is constructing the value
+ // wait until the waiter is signalled, then load the real value.
+ <-wait
+ value, _ = once.values.Load(key)
+ if _, isWaiter := value.(onceValueWaiter); isWaiter {
+ panic(fmt.Errorf("Once() waiter completed but key is still not valid"))
+ }
+ }
+
+ return value
+}
// Once computes a value the first time it is called with a given key per OncePer, and returns the
// value without recomputing when called with the same key. key must be hashable.
-func (once *OncePer) Once(key interface{}, value func() interface{}) interface{} {
+func (once *OncePer) Once(key OnceKey, value func() interface{}) interface{} {
// Fast path: check if the key is already in the map
if v, ok := once.values.Load(key); ok {
- return v
+ return once.maybeWaitFor(key, v)
}
- // Slow path: lock so that we don't call the value function twice concurrently
- once.valuesLock.Lock()
- defer once.valuesLock.Unlock()
-
- // Check again with the lock held
- if v, ok := once.values.Load(key); ok {
- return v
+ // Slow path: create a OnceValueWrapper and attempt to insert it
+ waiter := make(onceValueWaiter)
+ if v, loaded := once.values.LoadOrStore(key, waiter); loaded {
+ // Got a value, something else inserted its own waiter or a constructed value
+ return once.maybeWaitFor(key, v)
}
- // Still not in the map, call the value function and store it
+ // The waiter is inserted, call the value constructor, store it, and signal the waiter
v := value()
once.values.Store(key, v)
+ close(waiter)
return v
}
-func (once *OncePer) Get(key interface{}) interface{} {
+// Get returns the value previously computed with Once for a given key. If Once has not been called for the given
+// key Get will panic.
+func (once *OncePer) Get(key OnceKey) interface{} {
v, ok := once.values.Load(key)
if !ok {
panic(fmt.Errorf("Get() called before Once()"))
@@ -59,11 +73,13 @@
return v
}
-func (once *OncePer) OnceStringSlice(key interface{}, value func() []string) []string {
+// OnceStringSlice is the same as Once, but returns the value cast to a []string
+func (once *OncePer) OnceStringSlice(key OnceKey, value func() []string) []string {
return once.Once(key, func() interface{} { return value() }).([]string)
}
-func (once *OncePer) Once2StringSlice(key interface{}, value func() ([]string, []string)) ([]string, []string) {
+// OnceStringSlice is the same as Once, but returns two values cast to []string
+func (once *OncePer) Once2StringSlice(key OnceKey, value func() ([]string, []string)) ([]string, []string) {
type twoStringSlice [2][]string
s := once.Once(key, func() interface{} {
var s twoStringSlice
@@ -72,3 +88,21 @@
}).(twoStringSlice)
return s[0], s[1]
}
+
+// OnceKey is an opaque type to be used as the key in calls to Once.
+type OnceKey struct {
+ key interface{}
+}
+
+// NewOnceKey returns an opaque OnceKey object for the provided key. Two calls to NewOnceKey with the same key string
+// DO NOT produce the same OnceKey object.
+func NewOnceKey(key string) OnceKey {
+ return OnceKey{&key}
+}
+
+// NewCustomOnceKey returns an opaque OnceKey object for the provided key. The key can be any type that is valid as the
+// key in a map, i.e. comparable. Two calls to NewCustomOnceKey with key values that compare equal will return OnceKey
+// objects that access the same value stored with Once.
+func NewCustomOnceKey(key interface{}) OnceKey {
+ return OnceKey{key}
+}
diff --git a/android/onceper_test.go b/android/onceper_test.go
new file mode 100644
index 0000000..f27799b
--- /dev/null
+++ b/android/onceper_test.go
@@ -0,0 +1,146 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+ "testing"
+)
+
+func TestOncePer_Once(t *testing.T) {
+ once := OncePer{}
+ key := NewOnceKey("key")
+
+ a := once.Once(key, func() interface{} { return "a" }).(string)
+ b := once.Once(key, func() interface{} { return "b" }).(string)
+
+ if a != "a" {
+ t.Errorf(`first call to Once should return "a": %q`, a)
+ }
+
+ if b != "a" {
+ t.Errorf(`second call to Once with the same key should return "a": %q`, b)
+ }
+}
+
+func TestOncePer_Get(t *testing.T) {
+ once := OncePer{}
+ key := NewOnceKey("key")
+
+ a := once.Once(key, func() interface{} { return "a" }).(string)
+ b := once.Get(key).(string)
+
+ if a != "a" {
+ t.Errorf(`first call to Once should return "a": %q`, a)
+ }
+
+ if b != "a" {
+ t.Errorf(`Get with the same key should return "a": %q`, b)
+ }
+}
+
+func TestOncePer_Get_panic(t *testing.T) {
+ once := OncePer{}
+ key := NewOnceKey("key")
+
+ defer func() {
+ p := recover()
+
+ if p == nil {
+ t.Error("call to Get for unused key should panic")
+ }
+ }()
+
+ once.Get(key)
+}
+
+func TestOncePer_OnceStringSlice(t *testing.T) {
+ once := OncePer{}
+ key := NewOnceKey("key")
+
+ a := once.OnceStringSlice(key, func() []string { return []string{"a"} })
+ b := once.OnceStringSlice(key, func() []string { return []string{"a"} })
+
+ if a[0] != "a" {
+ t.Errorf(`first call to OnceStringSlice should return ["a"]: %q`, a)
+ }
+
+ if b[0] != "a" {
+ t.Errorf(`second call to OnceStringSlice with the same key should return ["a"]: %q`, b)
+ }
+}
+
+func TestOncePer_Once2StringSlice(t *testing.T) {
+ once := OncePer{}
+ key := NewOnceKey("key")
+
+ a, b := once.Once2StringSlice(key, func() ([]string, []string) { return []string{"a"}, []string{"b"} })
+ c, d := once.Once2StringSlice(key, func() ([]string, []string) { return []string{"c"}, []string{"d"} })
+
+ if a[0] != "a" || b[0] != "b" {
+ t.Errorf(`first call to Once2StringSlice should return ["a"], ["b"]: %q, %q`, a, b)
+ }
+
+ if c[0] != "a" || d[0] != "b" {
+ t.Errorf(`second call to Once2StringSlice with the same key should return ["a"], ["b"]: %q, %q`, c, d)
+ }
+}
+
+func TestNewOnceKey(t *testing.T) {
+ once := OncePer{}
+ key1 := NewOnceKey("key")
+ key2 := NewOnceKey("key")
+
+ a := once.Once(key1, func() interface{} { return "a" }).(string)
+ b := once.Once(key2, func() interface{} { return "b" }).(string)
+
+ if a != "a" {
+ t.Errorf(`first call to Once should return "a": %q`, a)
+ }
+
+ if b != "b" {
+ t.Errorf(`second call to Once with the NewOnceKey from same string should return "b": %q`, b)
+ }
+}
+
+func TestNewCustomOnceKey(t *testing.T) {
+ type key struct {
+ key string
+ }
+ once := OncePer{}
+ key1 := NewCustomOnceKey(key{"key"})
+ key2 := NewCustomOnceKey(key{"key"})
+
+ a := once.Once(key1, func() interface{} { return "a" }).(string)
+ b := once.Once(key2, func() interface{} { return "b" }).(string)
+
+ if a != "a" {
+ t.Errorf(`first call to Once should return "a": %q`, a)
+ }
+
+ if b != "a" {
+ t.Errorf(`second call to Once with the NewCustomOnceKey from equal key should return "a": %q`, b)
+ }
+}
+
+func TestOncePerReentrant(t *testing.T) {
+ once := OncePer{}
+ key1 := NewOnceKey("key")
+ key2 := NewOnceKey("key")
+
+ a := once.Once(key1, func() interface{} { return once.Once(key2, func() interface{} { return "a" }) })
+ if a != "a" {
+ t.Errorf(`reentrant Once should return "a": %q`, a)
+ }
+}
diff --git a/android/paths.go b/android/paths.go
index 4b84c97..31500ab 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -244,7 +244,7 @@
}
path := filepath.Clean(p)
if !strings.HasPrefix(path, prefix) {
- reportPathErrorf(ctx, "Path '%s' is not in module source directory '%s'", p, prefix)
+ reportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
continue
}
@@ -263,9 +263,9 @@
}
// PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's
-// local source directory. If none are provided, use the default if it exists.
+// local source directory. If input is nil, use the default if it exists. If input is empty, returns nil.
func PathsWithOptionalDefaultForModuleSrc(ctx ModuleContext, input []string, def string) Paths {
- if len(input) > 0 {
+ if input != nil {
return PathsForModuleSrc(ctx, input)
}
// Use Glob so that if the default doesn't exist, a dependency is added so that when it
@@ -505,7 +505,7 @@
// absolute path already checked by validateSafePath
if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
- return ret, fmt.Errorf("source path %s is in output", ret.String())
+ return ret, fmt.Errorf("source path %q is in output", ret.String())
}
return ret, err
@@ -521,7 +521,7 @@
// absolute path already checked by validatePath
if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
- return ret, fmt.Errorf("source path %s is in output", ret.String())
+ return ret, fmt.Errorf("source path %q is in output", ret.String())
}
return ret, nil
@@ -575,7 +575,7 @@
} else if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
reportPathErrorf(ctx, "%s: %s", path, err.Error())
} else if !exists {
- reportPathErrorf(ctx, "source path %s does not exist", path)
+ reportPathErrorf(ctx, "source path %q does not exist", path)
}
return path
}
@@ -697,6 +697,16 @@
return p.withRel(path)
}
+// ReplaceExtension creates a new OutputPath with the extension replaced with ext.
+func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
+ if strings.Contains(ext, "/") {
+ reportPathErrorf(ctx, "extension %q cannot contain /", ext)
+ }
+ ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext))
+ ret.rel = p.rel
+ return ret
+}
+
// PathForIntermediates returns an OutputPath representing the top-level
// intermediates directory.
func PathForIntermediates(ctx PathContext, paths ...string) OutputPath {
@@ -740,7 +750,7 @@
if exists, _, err := ctx.Fs().Exists(path.String()); err != nil {
reportPathErrorf(ctx, "%s: %s", path, err.Error())
} else if !exists {
- reportPathErrorf(ctx, "module source path %s does not exist", path)
+ reportPathErrorf(ctx, "module source path %q does not exist", path)
}
return path
diff --git a/android/paths_test.go b/android/paths_test.go
index 1ed0734..1972591 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -691,3 +691,15 @@
})
}
}
+
+func ExampleOutputPath_ReplaceExtension() {
+ ctx := &configErrorWrapper{
+ config: TestConfig("out", nil),
+ }
+ p := PathForOutput(ctx, "system/framework/boot.art")
+ p2 := p.ReplaceExtension(ctx, "oat")
+ fmt.Println(p, p2)
+
+ // Output:
+ // out/system/framework/boot.art out/system/framework/boot.oat
+}
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
index 42c7c2c..a047e47 100644
--- a/android/prebuilt_etc.go
+++ b/android/prebuilt_etc.go
@@ -20,11 +20,12 @@
"strings"
)
-// prebuilt_etc is for prebuilts that will be installed to
-// <partition>/etc/<subdir>
+// TODO(jungw): Now that it handles more than the ones in etc/, consider renaming this file.
func init() {
RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
+ RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
+ RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
PreDepsMutators(func(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
@@ -59,8 +60,10 @@
properties prebuiltEtcProperties
- sourceFilePath Path
- outputFilePath OutputPath
+ sourceFilePath Path
+ outputFilePath OutputPath
+ // The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
+ installDirBase string
installDirPath OutputPath
additionalDependencies *Paths
}
@@ -123,7 +126,7 @@
return
}
p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
- p.installDirPath = PathForModuleInstall(ctx, "etc", String(p.properties.Sub_dir))
+ p.installDirPath = PathForModuleInstall(ctx, p.installDirBase, String(p.properties.Sub_dir))
// This ensures that outputFilePath has the correct name for others to
// use, as the source file may have a different name.
@@ -145,7 +148,13 @@
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
fmt.Fprintln(w, "LOCAL_MODULE :=", name+nameSuffix)
fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC")
+ if p.commonProperties.Owner != nil {
+ 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())
@@ -167,8 +176,26 @@
p.AddProperties(&p.properties)
}
+// prebuilt_etc is for prebuilts that will be installed to <partition>/etc/<subdir>
func PrebuiltEtcFactory() Module {
- module := &PrebuiltEtc{}
+ module := &PrebuiltEtc{installDirBase: "etc"}
+ InitPrebuiltEtcModule(module)
+ // This module is device-only
+ InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
+ return module
+}
+
+func PrebuiltEtcHostFactory() Module {
+ module := &PrebuiltEtc{installDirBase: "etc"}
+ InitPrebuiltEtcModule(module)
+ // This module is host-only
+ InitAndroidArchModule(module, HostSupported, MultilibCommon)
+ return module
+}
+
+// prebuilt_usr_share is for prebuilts that will be installed to <partition>/usr/share/<subdir>
+func PrebuiltUserShareFactory() Module {
+ module := &PrebuiltEtc{installDirBase: "usr/share"}
InitPrebuiltEtcModule(module)
// This module is device-only
InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
@@ -187,7 +214,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 8ab978b..206f53b 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -15,8 +15,11 @@
package android
import (
+ "bufio"
+ "bytes"
"io/ioutil"
"os"
+ "strings"
"testing"
)
@@ -25,6 +28,8 @@
defer tearDown(buildDir)
ctx := NewTestArchContext()
ctx.RegisterModuleType("prebuilt_etc", ModuleFactoryAdaptor(PrebuiltEtcFactory))
+ ctx.RegisterModuleType("prebuilt_etc_host", ModuleFactoryAdaptor(PrebuiltEtcHostFactory))
+ ctx.RegisterModuleType("prebuilt_usr_share", ModuleFactoryAdaptor(PrebuiltUserShareFactory))
ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
ctx.BottomUp("prebuilt_etc", prebuiltEtcMutator).Parallel()
})
@@ -130,3 +135,78 @@
t.Errorf("expected bar.conf, got %q", p.outputFilePath.Base())
}
}
+
+func TestPrebuiltEtcAndroidMk(t *testing.T) {
+ ctx := testPrebuiltEtc(t, `
+ prebuilt_etc {
+ name: "foo",
+ src: "foo.conf",
+ owner: "abc",
+ filename_from_src: true,
+ }
+ `)
+
+ data := AndroidMkData{}
+ data.Required = append(data.Required, "modA", "moduleB")
+
+ expected := map[string]string{
+ "LOCAL_MODULE": "foo",
+ "LOCAL_MODULE_CLASS": "ETC",
+ "LOCAL_MODULE_OWNER": "abc",
+ "LOCAL_INSTALLED_MODULE_STEM": "foo.conf",
+ "LOCAL_REQUIRED_MODULES": "modA moduleB",
+ }
+
+ mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
+ buf := &bytes.Buffer{}
+ mod.AndroidMk().Custom(buf, "foo", "", "", data)
+ for k, expected := range expected {
+ found := false
+ scanner := bufio.NewScanner(bytes.NewReader(buf.Bytes()))
+ for scanner.Scan() {
+ line := scanner.Text()
+ tok := strings.Split(line, " := ")
+ if tok[0] == k {
+ found = true
+ if tok[1] != expected {
+ t.Errorf("Incorrect %s '%s', expected '%s'", k, tok[1], expected)
+ }
+ }
+ }
+
+ if !found {
+ t.Errorf("No %s defined, saw %s", k, buf.String())
+ }
+ }
+}
+
+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.")
+ }
+}
+
+func TestPrebuiltUserShareInstallDirPath(t *testing.T) {
+ ctx := testPrebuiltEtc(t, `
+ prebuilt_usr_share {
+ name: "foo.conf",
+ src: "foo.conf",
+ sub_dir: "bar",
+ }
+ `)
+
+ p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a_core").Module().(*PrebuiltEtc)
+ expected := "target/product/test_device/system/usr/share/bar"
+ if p.installDirPath.RelPathString() != expected {
+ t.Errorf("expected %q, got %q", expected, p.installDirPath.RelPathString())
+ }
+}
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index cd1ffae..b30ca1a 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -212,9 +212,6 @@
return p.prebuilt.Name(p.ModuleBase.Name())
}
-func (p *prebuiltModule) DepsMutator(ctx BottomUpMutatorContext) {
-}
-
func (p *prebuiltModule) GenerateAndroidBuildActions(ModuleContext) {
}
diff --git a/android/register.go b/android/register.go
index 6c88af1..19745fe 100644
--- a/android/register.go
+++ b/android/register.go
@@ -20,7 +20,7 @@
type moduleType struct {
name string
- factory blueprint.ModuleFactory
+ factory ModuleFactory
}
var moduleTypes []moduleType
@@ -40,8 +40,6 @@
parallel bool
}
-var mutators []*mutator
-
type ModuleFactory func() Module
// ModuleFactoryAdaptor wraps a ModuleFactory into a blueprint.ModuleFactory by converting a Module
@@ -65,7 +63,7 @@
}
func RegisterModuleType(name string, factory ModuleFactory) {
- moduleTypes = append(moduleTypes, moduleType{name, ModuleFactoryAdaptor(factory)})
+ moduleTypes = append(moduleTypes, moduleType{name, factory})
}
func RegisterSingletonType(name string, factory SingletonFactory) {
@@ -90,7 +88,7 @@
}
for _, t := range moduleTypes {
- ctx.RegisterModuleType(t.name, t.factory)
+ ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory))
}
for _, t := range singletons {
@@ -99,5 +97,17 @@
registerMutators(ctx.Context, preArch, preDeps, postDeps)
+ // Register makevars after other singletons so they can export values through makevars
+ ctx.RegisterSingletonType("makevars", SingletonFactoryAdaptor(makeVarsSingletonFunc))
+
+ // Register env last so that it can track all used environment variables
ctx.RegisterSingletonType("env", SingletonFactoryAdaptor(EnvSingleton))
}
+
+func ModuleTypeFactories() map[string]ModuleFactory {
+ ret := make(map[string]ModuleFactory)
+ for _, t := range moduleTypes {
+ ret[t.name] = t.factory
+ }
+ return ret
+}
diff --git a/android/rule_builder.go b/android/rule_builder.go
new file mode 100644
index 0000000..3b86947
--- /dev/null
+++ b/android/rule_builder.go
@@ -0,0 +1,443 @@
+// 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.
+
+package android
+
+import (
+ "fmt"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+// RuleBuilder provides an alternative to ModuleContext.Rule and ModuleContext.Build to add a command line to the build
+// graph.
+type RuleBuilder struct {
+ commands []*RuleBuilderCommand
+ installs RuleBuilderInstalls
+ temporariesSet map[string]bool
+ restat bool
+ missingDeps []string
+}
+
+// NewRuleBuilder returns a newly created RuleBuilder.
+func NewRuleBuilder() *RuleBuilder {
+ return &RuleBuilder{
+ temporariesSet: make(map[string]bool),
+ }
+}
+
+// RuleBuilderInstall is a tuple of install from and to locations.
+type RuleBuilderInstall struct {
+ From, To string
+}
+
+type RuleBuilderInstalls []RuleBuilderInstall
+
+// String returns the RuleBuilderInstalls in the form used by $(call copy-many-files) in Make, a space separated
+// list of from:to tuples.
+func (installs RuleBuilderInstalls) String() string {
+ sb := strings.Builder{}
+ for i, install := range installs {
+ if i != 0 {
+ sb.WriteRune(' ')
+ }
+ sb.WriteString(install.From)
+ sb.WriteRune(':')
+ sb.WriteString(install.To)
+ }
+ return sb.String()
+}
+
+// MissingDeps adds modules to the list of missing dependencies. If MissingDeps
+// is called with a non-empty input, any call to Build will result in a rule
+// that will print an error listing the missing dependencies and fail.
+// MissingDeps should only be called if Config.AllowMissingDependencies() is
+// true.
+func (r *RuleBuilder) MissingDeps(missingDeps []string) {
+ r.missingDeps = append(r.missingDeps, missingDeps...)
+}
+
+// Restat marks the rule as a restat rule, which will be passed to ModuleContext.Rule in BuildParams.Restat.
+func (r *RuleBuilder) Restat() *RuleBuilder {
+ r.restat = true
+ return r
+}
+
+// Install associates an output of the rule with an install location, which can be retrieved later using
+// RuleBuilder.Installs.
+func (r *RuleBuilder) Install(from, to string) {
+ r.installs = append(r.installs, RuleBuilderInstall{from, to})
+}
+
+// Command returns a new RuleBuilderCommand for the rule. The commands will be ordered in the rule by when they were
+// created by this method. That can be mutated through their methods in any order, as long as the mutations do not
+// race with any call to Build.
+func (r *RuleBuilder) Command() *RuleBuilderCommand {
+ command := &RuleBuilderCommand{}
+ r.commands = append(r.commands, command)
+ return command
+}
+
+// Temporary marks an output of a command as an intermediate file that will be used as an input to another command
+// in the same rule, and should not be listed in Outputs.
+func (r *RuleBuilder) Temporary(path string) {
+ r.temporariesSet[path] = true
+}
+
+// DeleteTemporaryFiles adds a command to the rule that deletes any outputs that have been marked using Temporary
+// when the rule runs. DeleteTemporaryFiles should be called after all calls to Temporary.
+func (r *RuleBuilder) DeleteTemporaryFiles() {
+ var temporariesList []string
+
+ for intermediate := range r.temporariesSet {
+ temporariesList = append(temporariesList, intermediate)
+ }
+ sort.Strings(temporariesList)
+
+ r.Command().Text("rm").Flag("-f").Outputs(temporariesList)
+}
+
+// Inputs returns the list of paths that were passed to the RuleBuilderCommand methods that take input paths, such
+// as RuleBuilderCommand.Input, RuleBuilderComand.Implicit, or RuleBuilderCommand.FlagWithInput. Inputs to a command
+// that are also outputs of another command in the same RuleBuilder are filtered out.
+func (r *RuleBuilder) Inputs() []string {
+ outputs := r.outputSet()
+
+ inputs := make(map[string]bool)
+ for _, c := range r.commands {
+ for _, input := range c.inputs {
+ if !outputs[input] {
+ inputs[input] = true
+ }
+ }
+ }
+
+ var inputList []string
+ for input := range inputs {
+ inputList = append(inputList, input)
+ }
+ sort.Strings(inputList)
+
+ return inputList
+}
+
+func (r *RuleBuilder) outputSet() map[string]bool {
+ outputs := make(map[string]bool)
+ for _, c := range r.commands {
+ for _, output := range c.outputs {
+ outputs[output] = true
+ }
+ }
+ return outputs
+}
+
+// Outputs returns the list of paths that were passed to the RuleBuilderCommand methods that take output paths, such
+// as RuleBuilderCommand.Output, RuleBuilderCommand.ImplicitOutput, or RuleBuilderCommand.FlagWithInput.
+func (r *RuleBuilder) Outputs() []string {
+ outputs := r.outputSet()
+
+ var outputList []string
+ for output := range outputs {
+ if !r.temporariesSet[output] {
+ outputList = append(outputList, output)
+ }
+ }
+ sort.Strings(outputList)
+ return outputList
+}
+
+// Installs returns the list of tuples passed to Install.
+func (r *RuleBuilder) Installs() RuleBuilderInstalls {
+ return append(RuleBuilderInstalls(nil), r.installs...)
+}
+
+func (r *RuleBuilder) toolsSet() map[string]bool {
+ tools := make(map[string]bool)
+ for _, c := range r.commands {
+ for _, tool := range c.tools {
+ tools[tool] = true
+ }
+ }
+
+ return tools
+}
+
+// Tools returns the list of paths that were passed to the RuleBuilderCommand.Tool method.
+func (r *RuleBuilder) Tools() []string {
+ toolsSet := r.toolsSet()
+
+ var toolsList []string
+ for tool := range toolsSet {
+ toolsList = append(toolsList, tool)
+ }
+ sort.Strings(toolsList)
+ return toolsList
+}
+
+// Commands returns a slice containing a the built command line for each call to RuleBuilder.Command.
+func (r *RuleBuilder) Commands() []string {
+ var commands []string
+ for _, c := range r.commands {
+ commands = append(commands, string(c.buf))
+ }
+ return commands
+}
+
+// BuilderContext is a subset of ModuleContext and SingletonContext.
+type BuilderContext interface {
+ PathContext
+ Rule(PackageContext, string, blueprint.RuleParams, ...string) blueprint.Rule
+ Build(PackageContext, BuildParams)
+}
+
+var _ BuilderContext = ModuleContext(nil)
+var _ BuilderContext = SingletonContext(nil)
+
+// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
+// Outputs.
+func (r *RuleBuilder) Build(pctx PackageContext, ctx BuilderContext, name string, desc string) {
+ // TODO: convert RuleBuilder arguments and storage to Paths
+ mctx, _ := ctx.(ModuleContext)
+ var inputs Paths
+ for _, input := range r.Inputs() {
+ // Module output paths
+ if mctx != nil {
+ rel, isRel := MaybeRel(ctx, PathForModuleOut(mctx).String(), input)
+ if isRel {
+ inputs = append(inputs, PathForModuleOut(mctx, rel))
+ continue
+ }
+ }
+
+ // Other output paths
+ rel, isRel := MaybeRel(ctx, PathForOutput(ctx).String(), input)
+ if isRel {
+ inputs = append(inputs, PathForOutput(ctx, rel))
+ continue
+ }
+
+ // TODO: remove this once boot image is moved to where PathForOutput can find it.
+ inputs = append(inputs, &unknownRulePath{input})
+ }
+
+ var outputs WritablePaths
+ for _, output := range r.Outputs() {
+ if mctx != nil {
+ rel := Rel(ctx, PathForModuleOut(mctx).String(), output)
+ outputs = append(outputs, PathForModuleOut(mctx, rel))
+ } else {
+ rel := Rel(ctx, PathForOutput(ctx).String(), output)
+ outputs = append(outputs, PathForOutput(ctx, rel))
+ }
+ }
+
+ if len(r.missingDeps) > 0 {
+ ctx.Build(pctx, BuildParams{
+ Rule: ErrorRule,
+ Outputs: outputs,
+ Description: desc,
+ Args: map[string]string{
+ "error": "missing dependencies: " + strings.Join(r.missingDeps, ", "),
+ },
+ })
+ return
+ }
+
+ if len(r.Commands()) > 0 {
+ ctx.Build(pctx, BuildParams{
+ Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
+ Command: strings.Join(proptools.NinjaEscape(r.Commands()), " && "),
+ CommandDeps: r.Tools(),
+ }),
+ Implicits: inputs,
+ Outputs: outputs,
+ Description: desc,
+ })
+ }
+}
+
+// RuleBuilderCommand is a builder for a command in a command line. It can be mutated by its methods to add to the
+// command and track dependencies. The methods mutate the RuleBuilderCommand in place, as well as return the
+// RuleBuilderCommand, so they can be used chained or unchained. All methods that add text implicitly add a single
+// space as a separator from the previous method.
+type RuleBuilderCommand struct {
+ buf []byte
+ inputs []string
+ outputs []string
+ tools []string
+}
+
+// Text adds the specified raw text to the command line. The text should not contain input or output paths or the
+// rule will not have them listed in its dependencies or outputs.
+func (c *RuleBuilderCommand) Text(text string) *RuleBuilderCommand {
+ if len(c.buf) > 0 {
+ c.buf = append(c.buf, ' ')
+ }
+ c.buf = append(c.buf, text...)
+ return c
+}
+
+// Textf adds the specified formatted text to the command line. The text should not contain input or output paths or
+// the rule will not have them listed in its dependencies or outputs.
+func (c *RuleBuilderCommand) Textf(format string, a ...interface{}) *RuleBuilderCommand {
+ return c.Text(fmt.Sprintf(format, a...))
+}
+
+// Flag adds the specified raw text to the command line. The text should not contain input or output paths or the
+// rule will not have them listed in its dependencies or outputs.
+func (c *RuleBuilderCommand) Flag(flag string) *RuleBuilderCommand {
+ return c.Text(flag)
+}
+
+// FlagWithArg adds the specified flag and argument text to the command line, with no separator between them. The flag
+// and argument should not contain input or output paths or the rule will not have them listed in its dependencies or
+// outputs.
+func (c *RuleBuilderCommand) FlagWithArg(flag, arg string) *RuleBuilderCommand {
+ return c.Text(flag + arg)
+}
+
+// FlagForEachArg adds the specified flag joined with each argument to the command line. The result is identical to
+// calling FlagWithArg for argument.
+func (c *RuleBuilderCommand) FlagForEachArg(flag string, args []string) *RuleBuilderCommand {
+ for _, arg := range args {
+ c.FlagWithArg(flag, arg)
+ }
+ return c
+}
+
+// FlagWithArg adds the specified flag and list of arguments to the command line, with the arguments joined by sep
+// and no separator between the flag and arguments. The flag and arguments should not contain input or output paths or
+// the rule will not have them listed in its dependencies or outputs.
+func (c *RuleBuilderCommand) FlagWithList(flag string, list []string, sep string) *RuleBuilderCommand {
+ return c.Text(flag + strings.Join(list, sep))
+}
+
+// Tool adds the specified tool path to the command line. The path will be also added to the dependencies returned by
+// RuleBuilder.Tools.
+func (c *RuleBuilderCommand) Tool(path string) *RuleBuilderCommand {
+ c.tools = append(c.tools, path)
+ return c.Text(path)
+}
+
+// Input adds the specified input path to the command line. The path will also be added to the dependencies returned by
+// RuleBuilder.Inputs.
+func (c *RuleBuilderCommand) Input(path string) *RuleBuilderCommand {
+ c.inputs = append(c.inputs, path)
+ return c.Text(path)
+}
+
+// Inputs adds the specified input paths to the command line, separated by spaces. The paths will also be added to the
+// dependencies returned by RuleBuilder.Inputs.
+func (c *RuleBuilderCommand) Inputs(paths []string) *RuleBuilderCommand {
+ for _, path := range paths {
+ c.Input(path)
+ }
+ return c
+}
+
+// Implicit adds the specified input path to the dependencies returned by RuleBuilder.Inputs without modifying the
+// command line.
+func (c *RuleBuilderCommand) Implicit(path string) *RuleBuilderCommand {
+ c.inputs = append(c.inputs, path)
+ return c
+}
+
+// Implicits adds the specified input paths to the dependencies returned by RuleBuilder.Inputs without modifying the
+// command line.
+func (c *RuleBuilderCommand) Implicits(paths []string) *RuleBuilderCommand {
+ c.inputs = append(c.inputs, paths...)
+ return c
+}
+
+// Output adds the specified output path to the command line. The path will also be added to the outputs returned by
+// RuleBuilder.Outputs.
+func (c *RuleBuilderCommand) Output(path string) *RuleBuilderCommand {
+ c.outputs = append(c.outputs, path)
+ return c.Text(path)
+}
+
+// Outputs adds the specified output paths to the command line, separated by spaces. The paths will also be added to
+// the outputs returned by RuleBuilder.Outputs.
+func (c *RuleBuilderCommand) Outputs(paths []string) *RuleBuilderCommand {
+ for _, path := range paths {
+ c.Output(path)
+ }
+ return c
+}
+
+// ImplicitOutput adds the specified output path to the dependencies returned by RuleBuilder.Outputs without modifying
+// the command line.
+func (c *RuleBuilderCommand) ImplicitOutput(path string) *RuleBuilderCommand {
+ c.outputs = append(c.outputs, path)
+ return c
+}
+
+// ImplicitOutputs adds the specified output paths to the dependencies returned by RuleBuilder.Outputs without modifying
+// the command line.
+func (c *RuleBuilderCommand) ImplicitOutputs(paths []string) *RuleBuilderCommand {
+ c.outputs = append(c.outputs, paths...)
+ return c
+}
+
+// FlagWithInput adds the specified flag and input path to the command line, with no separator between them. The path
+// will also be added to the dependencies returned by RuleBuilder.Inputs.
+func (c *RuleBuilderCommand) FlagWithInput(flag, path string) *RuleBuilderCommand {
+ c.inputs = append(c.inputs, path)
+ return c.Text(flag + path)
+}
+
+// FlagWithInputList adds the specified flag and input paths to the command line, with the inputs joined by sep
+// and no separator between the flag and inputs. The input paths will also be added to the dependencies returned by
+// RuleBuilder.Inputs.
+func (c *RuleBuilderCommand) FlagWithInputList(flag string, paths []string, sep string) *RuleBuilderCommand {
+ c.inputs = append(c.inputs, paths...)
+ return c.FlagWithList(flag, paths, sep)
+}
+
+// FlagForEachInput adds the specified flag joined with each input path to the command line. The input paths will also
+// be added to the dependencies returned by RuleBuilder.Inputs. The result is identical to calling FlagWithInput for
+// each input path.
+func (c *RuleBuilderCommand) FlagForEachInput(flag string, paths []string) *RuleBuilderCommand {
+ for _, path := range paths {
+ c.FlagWithInput(flag, path)
+ }
+ return c
+}
+
+// FlagWithOutput adds the specified flag and output path to the command line, with no separator between them. The path
+// will also be added to the outputs returned by RuleBuilder.Outputs.
+func (c *RuleBuilderCommand) FlagWithOutput(flag, path string) *RuleBuilderCommand {
+ c.outputs = append(c.outputs, path)
+ return c.Text(flag + path)
+}
+
+// String returns the command line.
+func (c *RuleBuilderCommand) String() string {
+ return string(c.buf)
+}
+
+type unknownRulePath struct {
+ path string
+}
+
+var _ Path = (*unknownRulePath)(nil)
+
+func (p *unknownRulePath) String() string { return p.path }
+func (p *unknownRulePath) Ext() string { return filepath.Ext(p.path) }
+func (p *unknownRulePath) Base() string { return filepath.Base(p.path) }
+func (p *unknownRulePath) Rel() string { return p.path }
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
new file mode 100644
index 0000000..f947348
--- /dev/null
+++ b/android/rule_builder_test.go
@@ -0,0 +1,313 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+func ExampleRuleBuilder() {
+ rule := NewRuleBuilder()
+
+ rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked")
+ rule.Command().Text("echo success")
+
+ // To add the command to the build graph:
+ // rule.Build(pctx, ctx, "link", "link")
+
+ fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
+ fmt.Printf("tools: %q\n", rule.Tools())
+ fmt.Printf("inputs: %q\n", rule.Inputs())
+ fmt.Printf("outputs: %q\n", rule.Outputs())
+
+ // Output:
+ // commands: "ld a.o b.o -o linked && echo success"
+ // tools: ["ld"]
+ // inputs: ["a.o" "b.o"]
+ // outputs: ["linked"]
+}
+
+func ExampleRuleBuilder_Temporary() {
+ rule := NewRuleBuilder()
+
+ rule.Command().Tool("cp").Input("a").Output("b")
+ rule.Command().Tool("cp").Input("b").Output("c")
+ rule.Temporary("b")
+
+ fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
+ fmt.Printf("tools: %q\n", rule.Tools())
+ fmt.Printf("inputs: %q\n", rule.Inputs())
+ fmt.Printf("outputs: %q\n", rule.Outputs())
+
+ // Output:
+ // commands: "cp a b && cp b c"
+ // tools: ["cp"]
+ // inputs: ["a"]
+ // outputs: ["c"]
+}
+
+func ExampleRuleBuilder_DeleteTemporaryFiles() {
+ rule := NewRuleBuilder()
+
+ rule.Command().Tool("cp").Input("a").Output("b")
+ rule.Command().Tool("cp").Input("b").Output("c")
+ rule.Temporary("b")
+ rule.DeleteTemporaryFiles()
+
+ fmt.Printf("commands: %q\n", strings.Join(rule.Commands(), " && "))
+ fmt.Printf("tools: %q\n", rule.Tools())
+ fmt.Printf("inputs: %q\n", rule.Inputs())
+ fmt.Printf("outputs: %q\n", rule.Outputs())
+
+ // Output:
+ // commands: "cp a b && cp b c && rm -f b"
+ // tools: ["cp"]
+ // inputs: ["a"]
+ // outputs: ["c"]
+}
+
+func ExampleRuleBuilder_Installs() {
+ rule := NewRuleBuilder()
+
+ rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked")
+ rule.Install("linked", "/bin/linked")
+ rule.Install("linked", "/sbin/linked")
+
+ fmt.Printf("rule.Installs().String() = %q\n", rule.Installs().String())
+
+ // Output:
+ // rule.Installs().String() = "linked:/bin/linked linked:/sbin/linked"
+}
+
+func ExampleRuleBuilderCommand() {
+ rule := NewRuleBuilder()
+
+ // chained
+ rule.Command().Tool("ld").Inputs([]string{"a.o", "b.o"}).FlagWithOutput("-o ", "linked")
+
+ // unchained
+ cmd := rule.Command()
+ cmd.Tool("ld")
+ cmd.Inputs([]string{"a.o", "b.o"})
+ cmd.FlagWithOutput("-o ", "linked")
+
+ // mixed:
+ cmd = rule.Command().Tool("ld")
+ cmd.Inputs([]string{"a.o", "b.o"})
+ cmd.FlagWithOutput("-o ", "linked")
+}
+
+func ExampleRuleBuilderCommand_Flag() {
+ fmt.Println(NewRuleBuilder().Command().
+ Tool("ls").Flag("-l"))
+ // Output:
+ // ls -l
+}
+
+func ExampleRuleBuilderCommand_FlagWithArg() {
+ fmt.Println(NewRuleBuilder().Command().
+ Tool("ls").
+ FlagWithArg("--sort=", "time"))
+ // Output:
+ // ls --sort=time
+}
+
+func ExampleRuleBuilderCommand_FlagForEachArg() {
+ fmt.Println(NewRuleBuilder().Command().
+ Tool("ls").
+ FlagForEachArg("--sort=", []string{"time", "size"}))
+ // Output:
+ // ls --sort=time --sort=size
+}
+
+func ExampleRuleBuilderCommand_FlagForEachInput() {
+ fmt.Println(NewRuleBuilder().Command().
+ Tool("turbine").
+ FlagForEachInput("--classpath ", []string{"a.jar", "b.jar"}))
+ // Output:
+ // turbine --classpath a.jar --classpath b.jar
+}
+
+func ExampleRuleBuilderCommand_FlagWithInputList() {
+ fmt.Println(NewRuleBuilder().Command().
+ Tool("java").
+ FlagWithInputList("-classpath=", []string{"a.jar", "b.jar"}, ":"))
+ // Output:
+ // java -classpath=a.jar:b.jar
+}
+
+func ExampleRuleBuilderCommand_FlagWithInput() {
+ fmt.Println(NewRuleBuilder().Command().
+ Tool("java").
+ FlagWithInput("-classpath=", "a"))
+ // Output:
+ // java -classpath=a
+}
+
+func ExampleRuleBuilderCommand_FlagWithList() {
+ fmt.Println(NewRuleBuilder().Command().
+ Tool("ls").
+ FlagWithList("--sort=", []string{"time", "size"}, ","))
+ // Output:
+ // ls --sort=time,size
+}
+
+func TestRuleBuilder(t *testing.T) {
+ rule := NewRuleBuilder()
+
+ cmd := rule.Command().
+ Flag("Flag").
+ FlagWithArg("FlagWithArg=", "arg").
+ FlagWithInput("FlagWithInput=", "input").
+ FlagWithOutput("FlagWithOutput=", "output").
+ Implicit("Implicit").
+ ImplicitOutput("ImplicitOutput").
+ Input("Input").
+ Output("Output").
+ Text("Text").
+ Tool("Tool")
+
+ rule.Command().
+ Text("command2").
+ Input("input2").
+ Output("output2").
+ Tool("tool2")
+
+ // Test updates to the first command after the second command has been started
+ cmd.Text("after command2")
+ // Test updating a command when the previous update did not replace the cmd variable
+ cmd.Text("old cmd")
+
+ // Test a command that uses the output of a previous command as an input
+ rule.Command().
+ Text("command3").
+ Input("input3").
+ Input("output2").
+ Output("output3")
+
+ wantCommands := []string{
+ "Flag FlagWithArg=arg FlagWithInput=input FlagWithOutput=output Input Output Text Tool after command2 old cmd",
+ "command2 input2 output2 tool2",
+ "command3 input3 output2 output3",
+ }
+ wantInputs := []string{"Implicit", "Input", "input", "input2", "input3"}
+ wantOutputs := []string{"ImplicitOutput", "Output", "output", "output2", "output3"}
+ wantTools := []string{"Tool", "tool2"}
+
+ if !reflect.DeepEqual(rule.Commands(), wantCommands) {
+ t.Errorf("\nwant rule.Commands() = %#v\n got %#v", wantCommands, rule.Commands())
+ }
+ if !reflect.DeepEqual(rule.Inputs(), wantInputs) {
+ t.Errorf("\nwant rule.Inputs() = %#v\n got %#v", wantInputs, rule.Inputs())
+ }
+ if !reflect.DeepEqual(rule.Outputs(), wantOutputs) {
+ t.Errorf("\nwant rule.Outputs() = %#v\n got %#v", wantOutputs, rule.Outputs())
+ }
+ if !reflect.DeepEqual(rule.Tools(), wantTools) {
+ t.Errorf("\nwant rule.Tools() = %#v\n got %#v", wantTools, rule.Tools())
+ }
+}
+
+func testRuleBuilderFactory() Module {
+ module := &testRuleBuilderModule{}
+ module.AddProperties(&module.properties)
+ InitAndroidModule(module)
+ return module
+}
+
+type testRuleBuilderModule struct {
+ ModuleBase
+ properties struct {
+ Src string
+ }
+}
+
+func (t *testRuleBuilderModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ in := PathForSource(ctx, t.properties.Src)
+ out := PathForModuleOut(ctx, ctx.ModuleName())
+
+ testRuleBuilder_Build(ctx, in, out)
+}
+
+type testRuleBuilderSingleton struct{}
+
+func testRuleBuilderSingletonFactory() Singleton {
+ return &testRuleBuilderSingleton{}
+}
+
+func (t *testRuleBuilderSingleton) GenerateBuildActions(ctx SingletonContext) {
+ in := PathForSource(ctx, "bar")
+ out := PathForOutput(ctx, "baz")
+ testRuleBuilder_Build(ctx, in, out)
+}
+
+func testRuleBuilder_Build(ctx BuilderContext, in Path, out WritablePath) {
+ rule := NewRuleBuilder()
+
+ rule.Command().Tool("cp").Input(in.String()).Output(out.String())
+
+ rule.Build(pctx, ctx, "rule", "desc")
+}
+
+func TestRuleBuilder_Build(t *testing.T) {
+ buildDir, err := ioutil.TempDir("", "soong_test_rule_builder")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(buildDir)
+
+ bp := `
+ rule_builder_test {
+ name: "foo",
+ src: "bar",
+ }
+ `
+
+ config := TestConfig(buildDir, nil)
+ ctx := NewTestContext()
+ ctx.MockFileSystem(map[string][]byte{
+ "Android.bp": []byte(bp),
+ "bar": nil,
+ "cp": nil,
+ })
+ ctx.RegisterModuleType("rule_builder_test", ModuleFactoryAdaptor(testRuleBuilderFactory))
+ ctx.RegisterSingletonType("rule_builder_test", SingletonFactoryAdaptor(testRuleBuilderSingletonFactory))
+ ctx.Register()
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ FailIfErrored(t, errs)
+
+ foo := ctx.ModuleForTests("foo", "").Rule("rule")
+
+ // TODO: make RuleParams accessible to tests and verify rule.Command().Tools() ends up in CommandDeps
+
+ if len(foo.Implicits) != 1 || foo.Implicits[0].String() != "bar" {
+ t.Errorf("want foo.Implicits = [%q], got %q", "bar", foo.Implicits.Strings())
+ }
+
+ wantOutput := filepath.Join(buildDir, ".intermediates", "foo", "foo")
+ if len(foo.Outputs) != 1 || foo.Outputs[0].String() != wantOutput {
+ t.Errorf("want foo.Outputs = [%q], got %q", wantOutput, foo.Outputs.Strings())
+ }
+
+}
diff --git a/android/singleton.go b/android/singleton.go
index f926435..05ec6b5 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -22,6 +22,7 @@
// SingletonContext
type SingletonContext interface {
Config() Config
+ DeviceConfig() DeviceConfig
ModuleName(module blueprint.Module) string
ModuleDir(module blueprint.Module) string
@@ -93,6 +94,10 @@
return s.SingletonContext.Config().(Config)
}
+func (s singletonContextAdaptor) DeviceConfig() DeviceConfig {
+ return DeviceConfig{s.Config().deviceConfig}
+}
+
func (s singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
s.SingletonContext.Variable(pctx.PackageContext, name, value)
}
diff --git a/android/variable.go b/android/variable.go
index 2cccd50..dc880b8 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -144,18 +144,18 @@
Platform_vndk_version *string `json:",omitempty"`
Platform_systemsdk_versions []string `json:",omitempty"`
- DeviceName *string `json:",omitempty"`
- DeviceArch *string `json:",omitempty"`
- DeviceArchVariant *string `json:",omitempty"`
- DeviceCpuVariant *string `json:",omitempty"`
- DeviceAbi *[]string `json:",omitempty"`
- DeviceVndkVersion *string `json:",omitempty"`
- DeviceSystemSdkVersions *[]string `json:",omitempty"`
+ DeviceName *string `json:",omitempty"`
+ DeviceArch *string `json:",omitempty"`
+ DeviceArchVariant *string `json:",omitempty"`
+ DeviceCpuVariant *string `json:",omitempty"`
+ DeviceAbi []string `json:",omitempty"`
+ DeviceVndkVersion *string `json:",omitempty"`
+ DeviceSystemSdkVersions []string `json:",omitempty"`
- DeviceSecondaryArch *string `json:",omitempty"`
- DeviceSecondaryArchVariant *string `json:",omitempty"`
- DeviceSecondaryCpuVariant *string `json:",omitempty"`
- DeviceSecondaryAbi *[]string `json:",omitempty"`
+ DeviceSecondaryArch *string `json:",omitempty"`
+ DeviceSecondaryArchVariant *string `json:",omitempty"`
+ DeviceSecondaryCpuVariant *string `json:",omitempty"`
+ DeviceSecondaryAbi []string `json:",omitempty"`
HostArch *string `json:",omitempty"`
HostSecondaryArch *string `json:",omitempty"`
@@ -164,14 +164,14 @@
CrossHostArch *string `json:",omitempty"`
CrossHostSecondaryArch *string `json:",omitempty"`
- ResourceOverlays *[]string `json:",omitempty"`
- EnforceRROTargets *[]string `json:",omitempty"`
- EnforceRROExcludedOverlays *[]string `json:",omitempty"`
+ ResourceOverlays []string `json:",omitempty"`
+ EnforceRROTargets []string `json:",omitempty"`
+ EnforceRROExcludedOverlays []string `json:",omitempty"`
- AAPTCharacteristics *string `json:",omitempty"`
- AAPTConfig *[]string `json:",omitempty"`
- AAPTPreferredConfig *string `json:",omitempty"`
- AAPTPrebuiltDPI *[]string `json:",omitempty"`
+ AAPTCharacteristics *string `json:",omitempty"`
+ AAPTConfig []string `json:",omitempty"`
+ AAPTPreferredConfig *string `json:",omitempty"`
+ AAPTPrebuiltDPI []string `json:",omitempty"`
DefaultAppCertificate *string `json:",omitempty"`
@@ -207,14 +207,16 @@
DisableDexPreoptModules []string `json:",omitempty"`
DexPreoptProfileDir *string `json:",omitempty"`
- IntegerOverflowExcludePaths *[]string `json:",omitempty"`
+ IntegerOverflowExcludePaths []string `json:",omitempty"`
- EnableCFI *bool `json:",omitempty"`
- CFIExcludePaths *[]string `json:",omitempty"`
- CFIIncludePaths *[]string `json:",omitempty"`
+ EnableCFI *bool `json:",omitempty"`
+ CFIExcludePaths []string `json:",omitempty"`
+ CFIIncludePaths []string `json:",omitempty"`
- EnableXOM *bool `json:",omitempty"`
- XOMExcludePaths *[]string `json:",omitempty"`
+ DisableScudo *bool `json:",omitempty"`
+
+ EnableXOM *bool `json:",omitempty"`
+ XOMExcludePaths []string `json:",omitempty"`
VendorPath *string `json:",omitempty"`
OdmPath *string `json:",omitempty"`
@@ -224,9 +226,9 @@
ClangTidy *bool `json:",omitempty"`
TidyChecks *string `json:",omitempty"`
- NativeCoverage *bool `json:",omitempty"`
- CoveragePaths *[]string `json:",omitempty"`
- CoverageExcludePaths *[]string `json:",omitempty"`
+ NativeCoverage *bool `json:",omitempty"`
+ CoveragePaths []string `json:",omitempty"`
+ CoverageExcludePaths []string `json:",omitempty"`
DevicePrefer32BitApps *bool `json:",omitempty"`
DevicePrefer32BitExecutables *bool `json:",omitempty"`
@@ -276,10 +278,9 @@
EnforceSystemCertificate *bool `json:",omitempty"`
EnforceSystemCertificateWhitelist []string `json:",omitempty"`
- // TODO(ccross): move these to a Singleton in Soong
- HiddenAPIStubFlags *string `json:",omitempty"`
- HiddenAPIFlags *string `json:",omitempty"`
- HiddenAPIExtraAppUsageJars []string `json:",omitempty"`
+ ProductHiddenAPIStubs []string `json:",omitempty"`
+ ProductHiddenAPIStubsSystem []string `json:",omitempty"`
+ ProductHiddenAPIStubsTest []string `json:",omitempty"`
}
func boolPtr(v bool) *bool {
@@ -306,16 +307,16 @@
DeviceArch: stringPtr("arm64"),
DeviceArchVariant: stringPtr("armv8-a"),
DeviceCpuVariant: stringPtr("generic"),
- DeviceAbi: &[]string{"arm64-v8a"},
+ DeviceAbi: []string{"arm64-v8a"},
DeviceSecondaryArch: stringPtr("arm"),
DeviceSecondaryArchVariant: stringPtr("armv8-a"),
DeviceSecondaryCpuVariant: stringPtr("generic"),
- DeviceSecondaryAbi: &[]string{"armeabi-v7a", "armeabi"},
+ DeviceSecondaryAbi: []string{"armeabi-v7a", "armeabi"},
- AAPTConfig: &[]string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
+ AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
AAPTPreferredConfig: stringPtr("xhdpi"),
AAPTCharacteristics: stringPtr("nosdcard"),
- AAPTPrebuiltDPI: &[]string{"xhdpi", "xxhdpi"},
+ AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"},
Malloc_not_svelte: boolPtr(true),
Safestack: boolPtr(false),
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index aef8944..1ecda2d 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -188,6 +188,8 @@
"LOCAL_EXPORT_PACKAGE_RESOURCES": "export_package_resources",
"LOCAL_PRIVILEGED_MODULE": "privileged",
"LOCAL_AAPT_INCLUDE_ALL_RESOURCES": "aapt_include_all_resources",
+ "LOCAL_USE_EMBEDDED_NATIVE_LIBS": "use_embedded_native_libs",
+ "LOCAL_USE_EMBEDDED_DEX": "use_embedded_dex",
"LOCAL_DEX_PREOPT": "dex_preopt.enabled",
"LOCAL_DEX_PREOPT_APP_IMAGE": "dex_preopt.app_image",
diff --git a/apex/apex.go b/apex/apex.go
index f6daf9b..7633ad2 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -136,7 +136,9 @@
pctx.HostBinToolVariable("zip2zip", "zip2zip")
pctx.HostBinToolVariable("zipalign", "zipalign")
- android.RegisterModuleType("apex", ApexBundleFactory)
+ android.RegisterModuleType("apex", apexBundleFactory)
+ android.RegisterModuleType("apex_test", testApexBundleFactory)
+ android.RegisterModuleType("apex_defaults", defaultsFactory)
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("apex_deps", apexDepsMutator)
@@ -147,13 +149,18 @@
// Mark the direct and transitive dependencies of apex bundles so that they
// can be built for the apex bundles.
func apexDepsMutator(mctx android.TopDownMutatorContext) {
- if _, ok := mctx.Module().(*apexBundle); ok {
+ if a, ok := mctx.Module().(*apexBundle); ok {
apexBundleName := mctx.ModuleName()
mctx.WalkDeps(func(child, parent android.Module) bool {
depName := mctx.OtherModuleName(child)
// If the parent is apexBundle, this child is directly depended.
_, directDep := parent.(*apexBundle)
- android.UpdateApexDependency(apexBundleName, depName, directDep)
+ if a.installable() && !a.testApex {
+ // TODO(b/123892969): Workaround for not having any way to annotate test-apexs
+ // non-installable apex's cannot be installed and so should not prevent libraries from being
+ // installed to the system.
+ android.UpdateApexDependency(apexBundleName, depName, directDep)
+ }
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() {
am.BuildForApex(apexBundleName)
@@ -205,6 +212,10 @@
// "apex_manifest.json"
Manifest *string
+ // AndroidManifest.xml file used for the zip container of this APEX bundle.
+ // If unspecified, a default one is automatically generated.
+ AndroidManifest *string
+
// Determines the file contexts file for setting security context to each file in this APEX bundle.
// Specifically, when this is set to <value>, /system/sepolicy/apex/<value>_file_contexts file is
// used.
@@ -245,6 +256,9 @@
Ignore_system_library_special_case *bool
Multilib apexMultilibProperties
+
+ // List of sanitizer names that this APEX is enabled for
+ SanitizerNames []string `blueprint:"mutated"`
}
type apexTargetBundleProperties struct {
@@ -274,6 +288,7 @@
etc apexFileClass = iota
nativeSharedLib
nativeExecutable
+ shBinary
javaSharedLib
)
@@ -333,7 +348,7 @@
return "ETC"
case nativeSharedLib:
return "SHARED_LIBRARIES"
- case nativeExecutable:
+ case nativeExecutable, shBinary:
return "EXECUTABLES"
case javaSharedLib:
return "JAVA_LIBRARIES"
@@ -368,6 +383,8 @@
filesInfo []apexFile
flattened bool
+
+ testApex bool
}
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
@@ -484,18 +501,24 @@
{Mutator: "arch", Variation: "android_common"},
}, javaLibTag, a.properties.Java_libs...)
- if !ctx.Config().FlattenApex() || ctx.Config().UnbundledBuild() {
- if String(a.properties.Key) == "" {
- ctx.ModuleErrorf("key is missing")
- return
- }
- ctx.AddDependency(ctx.Module(), keyTag, String(a.properties.Key))
-
- cert := android.SrcIsModule(String(a.properties.Certificate))
- if cert != "" {
- ctx.AddDependency(ctx.Module(), certificateTag, cert)
- }
+ if String(a.properties.Key) == "" {
+ ctx.ModuleErrorf("key is missing")
+ return
}
+ ctx.AddDependency(ctx.Module(), keyTag, String(a.properties.Key))
+
+ cert := android.SrcIsModule(a.getCertString(ctx))
+ if cert != "" {
+ ctx.AddDependency(ctx.Module(), certificateTag, cert)
+ }
+}
+
+func (a *apexBundle) getCertString(ctx android.BaseContext) string {
+ certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
+ if overridden {
+ return ":" + certificate
+ }
+ return String(a.properties.Certificate)
}
func (a *apexBundle) Srcs() android.Paths {
@@ -518,7 +541,18 @@
}
}
+func (a *apexBundle) EnableSanitizer(sanitizerName string) {
+ if !android.InList(sanitizerName, a.properties.SanitizerNames) {
+ a.properties.SanitizerNames = append(a.properties.SanitizerNames, sanitizerName)
+ }
+}
+
func (a *apexBundle) IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool {
+ if android.InList(sanitizerName, a.properties.SanitizerNames) {
+ return true
+ }
+
+ // Then follow the global setting
globalSanitizerNames := []string{}
if a.Host() {
globalSanitizerNames = ctx.Config().SanitizeHost()
@@ -540,6 +574,7 @@
case "lib64":
dirInApex = "lib64"
}
+ dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath())
if !cc.Arch().Native {
dirInApex = filepath.Join(dirInApex, cc.Arch().ArchType.String())
}
@@ -564,11 +599,19 @@
}
func getCopyManifestForExecutable(cc *cc.Module) (fileToCopy android.Path, dirInApex string) {
+ // TODO(b/123721777) respect relative_install_path also for binaries
+ // dirInApex = filepath.Join("bin", cc.RelativeInstallPath())
dirInApex = "bin"
fileToCopy = cc.OutputFile().Path()
return
}
+func getCopyManifestForShBinary(sh *android.ShBinary) (fileToCopy android.Path, dirInApex string) {
+ dirInApex = filepath.Join("bin", sh.SubDir())
+ fileToCopy = sh.OutputFile()
+ return
+}
+
func getCopyManifestForJavaLibrary(java *java.Library) (fileToCopy android.Path, dirInApex string) {
dirInApex = "javalib"
fileToCopy = java.DexJarFile()
@@ -625,8 +668,11 @@
fileToCopy, dirInApex := getCopyManifestForExecutable(cc)
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, nativeExecutable, cc, cc.Symlinks()})
return true
+ } else if sh, ok := child.(*android.ShBinary); ok {
+ fileToCopy, dirInApex := getCopyManifestForShBinary(sh)
+ filesInfo = append(filesInfo, apexFile{fileToCopy, depName, dirInApex, shBinary, sh, nil})
} else {
- ctx.PropertyErrorf("binaries", "%q is not a cc_binary module", depName)
+ ctx.PropertyErrorf("binaries", "%q is neithher cc_binary nor sh_binary", depName)
}
case javaLibTag:
if java, ok := child.(*java.Library); ok {
@@ -687,7 +733,7 @@
})
a.flattened = ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
- if !a.flattened && keyFile == nil {
+ if keyFile == nil {
ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key))
return
}
@@ -724,11 +770,12 @@
a.buildUnflattenedApex(ctx, keyFile, pubKeyFile, certificate, zipApex)
}
if a.apexTypes.image() {
- if ctx.Config().FlattenApex() {
- a.buildFlattenedApex(ctx)
- } else {
- a.buildUnflattenedApex(ctx, keyFile, pubKeyFile, certificate, imageApex)
- }
+ // Build rule for unflattened APEX is created even when ctx.Config().FlattenApex()
+ // is true. This is to support referencing APEX via ":<module_name" syntax
+ // in other modules. It is in AndroidMk where the selection of flattened
+ // or unflattened APEX is made.
+ a.buildUnflattenedApex(ctx, keyFile, pubKeyFile, certificate, imageApex)
+ a.buildFlattenedApex(ctx)
}
}
@@ -842,6 +889,12 @@
optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
}
+ if a.properties.AndroidManifest != nil {
+ androidManifestFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.AndroidManifest))
+ implicitInputs = append(implicitInputs, androidManifestFile)
+ optFlags = append(optFlags, "--android_manifest "+androidManifestFile.String())
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: apexRule,
Implicits: implicitInputs,
@@ -907,7 +960,7 @@
})
// Install to $OUT/soong/{target,host}/.../apex
- if a.installable() {
+ if a.installable() && (!ctx.Config().FlattenApex() || apexType.zip()) {
ctx.InstallFile(android.PathForModuleInstall(ctx, "apex"), ctx.ModuleName()+suffix, a.outputFiles[apexType])
}
}
@@ -927,9 +980,11 @@
})
a.filesInfo = append(a.filesInfo, apexFile{copiedManifest, ctx.ModuleName() + ".apex_manifest.json", ".", etc, nil, nil})
- for _, fi := range a.filesInfo {
- dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir)
- ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile)
+ if ctx.Config().FlattenApex() {
+ for _, fi := range a.filesInfo {
+ dir := filepath.Join("apex", ctx.ModuleName(), fi.installDir)
+ ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile)
+ }
}
}
}
@@ -950,91 +1005,99 @@
}}
}
+func (a *apexBundle) androidMkForFiles(w io.Writer, name, moduleDir string, apexType apexPackaging) []string {
+ moduleNames := []string{}
+
+ for _, fi := range a.filesInfo {
+ if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake {
+ continue
+ }
+ if !android.InList(fi.moduleName, moduleNames) {
+ moduleNames = append(moduleNames, fi.moduleName)
+ }
+ fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
+ fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
+ fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
+ if a.flattened && apexType.image() {
+ // /system/apex/<name>/{lib|framework|...}
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)",
+ a.installDir.RelPathString(), name, fi.installDir))
+ } else {
+ // /apex/<name>/{lib|framework|...}
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(PRODUCT_OUT)",
+ "apex", name, fi.installDir))
+ }
+ fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
+ fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake())
+ if fi.module != nil {
+ archStr := fi.module.Target().Arch.ArchType.String()
+ host := false
+ switch fi.module.Target().Os.Class {
+ case android.Host:
+ if archStr != "common" {
+ fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
+ }
+ host = true
+ case android.HostCross:
+ if archStr != "common" {
+ fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
+ }
+ host = true
+ case android.Device:
+ if archStr != "common" {
+ fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
+ }
+ }
+ if host {
+ makeOs := fi.module.Target().Os.String()
+ if fi.module.Target().Os == android.Linux || fi.module.Target().Os == android.LinuxBionic {
+ makeOs = "linux"
+ }
+ fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs)
+ fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
+ }
+ }
+ if fi.class == javaSharedLib {
+ javaModule := fi.module.(*java.Library)
+ // soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar Therefore
+ // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
+ // we will have foo.jar.jar
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".jar"))
+ fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
+ fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
+ fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
+ fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
+ fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
+ } else if fi.class == nativeSharedLib || fi.class == nativeExecutable {
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
+ if cc, ok := fi.module.(*cc.Module); ok && cc.UnstrippedOutputFile() != nil {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
+ }
+ fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
+ } else {
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
+ fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
+ }
+ }
+ return moduleNames
+}
+
func (a *apexBundle) androidMkForType(apexType apexPackaging) android.AndroidMkData {
return android.AndroidMkData{
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
moduleNames := []string{}
- for _, fi := range a.filesInfo {
- if !android.InList(fi.moduleName, moduleNames) {
- moduleNames = append(moduleNames, fi.moduleName)
- }
+ if a.installable() {
+ moduleNames = a.androidMkForFiles(w, name, moduleDir, apexType)
}
- for _, fi := range a.filesInfo {
- if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake {
- continue
- }
- fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
- fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
- fmt.Fprintln(w, "LOCAL_MODULE :=", fi.moduleName)
- if a.flattened {
- // /system/apex/<name>/{lib|framework|...}
- fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(OUT_DIR)",
- a.installDir.RelPathString(), name, fi.installDir))
- } else {
- // /apex/<name>/{lib|framework|...}
- fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", filepath.Join("$(PRODUCT_OUT)",
- "apex", name, fi.installDir))
- }
- fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", fi.builtFile.String())
- fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.NameInMake())
- fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
- if fi.module != nil {
- archStr := fi.module.Target().Arch.ArchType.String()
- host := false
- switch fi.module.Target().Os.Class {
- case android.Host:
- if archStr != "common" {
- fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
- }
- host = true
- case android.HostCross:
- if archStr != "common" {
- fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
- }
- host = true
- case android.Device:
- if archStr != "common" {
- fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
- }
- }
- if host {
- makeOs := fi.module.Target().Os.String()
- if fi.module.Target().Os == android.Linux || fi.module.Target().Os == android.LinuxBionic {
- makeOs = "linux"
- }
- fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs)
- fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
- }
- }
- if fi.class == javaSharedLib {
- javaModule := fi.module.(*java.Library)
- // soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar Therefore
- // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
- // we will have foo.jar.jar
- fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.builtFile.Base(), ".jar"))
- fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
- fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
- fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
- fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
- fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
- } else if fi.class == nativeSharedLib || fi.class == nativeExecutable {
- fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
- if cc, ok := fi.module.(*cc.Module); ok && cc.UnstrippedOutputFile() != nil {
- fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
- }
- fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
- } else {
- fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.builtFile.Base())
- fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
- }
- }
if a.flattened && apexType.image() {
// Only image APEXes can be flattened.
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir)
fmt.Fprintln(w, "LOCAL_MODULE :=", name)
- fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
+ if len(moduleNames) > 0 {
+ fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
+ }
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
} else {
// zip-apex is the less common type so have the name refer to the image-apex
@@ -1051,7 +1114,9 @@
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", String(a.properties.Key))
- fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " "))
+ if len(moduleNames) > 0 {
+ fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " "))
+ }
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
if apexType == imageApex {
@@ -1061,9 +1126,18 @@
}}
}
-func ApexBundleFactory() android.Module {
+func testApexBundleFactory() android.Module {
+ return ApexBundleFactory( /*testApex*/ true)
+}
+
+func apexBundleFactory() android.Module {
+ return ApexBundleFactory( /*testApex*/ false)
+}
+
+func ApexBundleFactory(testApex bool) android.Module {
module := &apexBundle{
outputFiles: map[apexPackaging]android.WritablePath{},
+ testApex: testApex,
}
module.AddProperties(&module.properties)
module.AddProperties(&module.targetProperties)
@@ -1074,3 +1148,31 @@
android.InitDefaultableModule(module)
return module
}
+
+//
+// Defaults
+//
+type Defaults struct {
+ android.ModuleBase
+ android.DefaultsModuleBase
+}
+
+func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+
+func defaultsFactory() android.Module {
+ return DefaultsFactory()
+}
+
+func DefaultsFactory(props ...interface{}) android.Module {
+ module := &Defaults{}
+
+ module.AddProperties(props...)
+ module.AddProperties(
+ &apexBundleProperties{},
+ &apexTargetBundleProperties{},
+ )
+
+ android.InitDefaultsModule(module)
+ return module
+}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 9d33060..13ddb55 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -24,6 +24,7 @@
"android/soong/android"
"android/soong/cc"
+ "android/soong/java"
)
func testApex(t *testing.T, bp string) *android.TestContext {
@@ -31,8 +32,11 @@
defer teardown(buildDir)
ctx := android.NewTestArchContext()
- ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(ApexBundleFactory))
+ ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory))
+ ctx.RegisterModuleType("apex_test", android.ModuleFactoryAdaptor(testApexBundleFactory))
ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory))
+ ctx.RegisterModuleType("apex_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.TopDown("apex_deps", apexDepsMutator)
@@ -47,6 +51,8 @@
ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
ctx.RegisterModuleType("prebuilt_etc", android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory))
+ ctx.RegisterModuleType("sh_binary", android.ModuleFactoryAdaptor(android.ShBinaryFactory))
+ ctx.RegisterModuleType("android_app_certificate", android.ModuleFactoryAdaptor(java.AndroidAppCertificateFactory))
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("image", cc.ImageMutator).Parallel()
ctx.BottomUp("link", cc.LinkageMutator).Parallel()
@@ -134,18 +140,23 @@
`
ctx.MockFileSystem(map[string][]byte{
- "Android.bp": []byte(bp),
- "build/target/product/security": nil,
- "apex_manifest.json": nil,
- "system/sepolicy/apex/myapex-file_contexts": nil,
- "system/sepolicy/apex/otherapex-file_contexts": nil,
- "mylib.cpp": nil,
- "myprebuilt": nil,
- "my_include": nil,
- "vendor/foo/devkeys/test.x509.pem": nil,
- "vendor/foo/devkeys/test.pk8": nil,
- "vendor/foo/devkeys/testkey.avbpubkey": nil,
- "vendor/foo/devkeys/testkey.pem": nil,
+ "Android.bp": []byte(bp),
+ "build/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "system/sepolicy/apex/myapex-file_contexts": nil,
+ "system/sepolicy/apex/myapex_keytest-file_contexts": nil,
+ "system/sepolicy/apex/otherapex-file_contexts": nil,
+ "mylib.cpp": nil,
+ "myprebuilt": nil,
+ "my_include": nil,
+ "vendor/foo/devkeys/test.x509.pem": nil,
+ "vendor/foo/devkeys/test.pk8": nil,
+ "testkey.x509.pem": nil,
+ "testkey.pk8": nil,
+ "testkey.override.x509.pem": nil,
+ "testkey.override.pk8": nil,
+ "vendor/foo/devkeys/testkey.avbpubkey": nil,
+ "vendor/foo/devkeys/testkey.pem": nil,
})
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
@@ -164,6 +175,7 @@
config = android.TestArchConfig(buildDir, nil)
config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
config.TestProductVariables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
+ config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
return
}
@@ -200,8 +212,8 @@
// Minimal test
func TestBasicApex(t *testing.T) {
ctx := testApex(t, `
- apex {
- name: "myapex",
+ apex_defaults {
+ name: "myapex-defaults",
key: "myapex.key",
native_shared_libs: ["mylib"],
multilib: {
@@ -211,6 +223,11 @@
}
}
+ apex {
+ name: "myapex",
+ defaults: ["myapex-defaults"],
+ }
+
apex_key {
name: "myapex.key",
public_key: "testkey.avbpubkey",
@@ -615,7 +632,10 @@
apex {
name: "myapex",
key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ binaries: ["mybin"],
prebuilts: ["myetc"],
+ compile_multilib: "both",
}
apex_key {
@@ -629,15 +649,43 @@
src: "myprebuilt",
sub_dir: "foo/bar",
}
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ relative_install_path: "foo/bar",
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_binary {
+ name: "mybin",
+ srcs: ["mylib.cpp"],
+ relative_install_path: "foo/bar",
+ system_shared_libs: [],
+ static_executable: true,
+ stl: "none",
+ }
`)
generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("generateFsConfig")
dirs := strings.Split(generateFsRule.Args["exec_paths"], " ")
- // Ensure that etc, etc/foo, and etc/foo/bar are all listed
+ // Ensure that the subdirectories are all listed
ensureListContains(t, dirs, "etc")
ensureListContains(t, dirs, "etc/foo")
ensureListContains(t, dirs, "etc/foo/bar")
+ ensureListContains(t, dirs, "lib64")
+ ensureListContains(t, dirs, "lib64/foo")
+ ensureListContains(t, dirs, "lib64/foo/bar")
+ ensureListContains(t, dirs, "lib")
+ ensureListContains(t, dirs, "lib/foo")
+ ensureListContains(t, dirs, "lib/foo/bar")
+
+ // TODO(b/123721777) respect relative path for binaries
+ // ensureListContains(t, dirs, "bin")
+ // ensureListContains(t, dirs, "bin/foo")
+ // ensureListContains(t, dirs, "bin/foo/bar")
}
func TestUseVendor(t *testing.T) {
@@ -733,8 +781,9 @@
func TestKeys(t *testing.T) {
ctx := testApex(t, `
apex {
- name: "myapex",
+ name: "myapex_keytest",
key: "myapex.key",
+ certificate: ":myapex.certificate",
native_shared_libs: ["mylib"],
}
@@ -751,6 +800,16 @@
private_key: "testkey.pem",
}
+ android_app_certificate {
+ name: "myapex.certificate",
+ certificate: "testkey",
+ }
+
+ android_app_certificate {
+ name: "myapex.certificate.override",
+ certificate: "testkey.override",
+ }
+
`)
// check the APEX keys
@@ -765,11 +824,11 @@
"vendor/foo/devkeys/testkey.pem")
}
- // check the APK certs
- certs := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk").Args["certificates"]
- if certs != "vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8" {
+ // check the APK certs. It should be overridden to myapex.certificate.override
+ certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"]
+ if certs != "testkey.override.x509.pem testkey.override.pk8" {
t.Errorf("cert and private key %q are not %q", certs,
- "vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8")
+ "testkey.override.509.pem testkey.override.pk8")
}
}
@@ -865,6 +924,105 @@
ensureContains(t, cFlags, "-Imy_include")
}
+func TestNonTestApex(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib_common"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib_common",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ module := ctx.ModuleForTests("myapex", "android_common_myapex")
+ apexRule := module.Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+
+ if apex, ok := module.Module().(*apexBundle); !ok || apex.testApex {
+ t.Log("Apex was a test apex!")
+ t.Fail()
+ }
+ // Ensure that main rule creates an output
+ ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
+
+ // Ensure that apex variant is created for the direct dep
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared_myapex")
+
+ // Ensure that both direct and indirect deps are copied into apex
+ ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so")
+
+ // Ensure that the platform variant ends with _core_shared
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared")
+
+ if !android.InAnyApex("mylib_common") {
+ t.Log("Found mylib_common not in any apex!")
+ t.Fail()
+ }
+}
+
+func TestTestApex(t *testing.T) {
+ if android.InAnyApex("mylib_common_test") {
+ t.Fatal("mylib_common_test must not be used in any other tests since this checks that global state is not updated in an illegal way!")
+ }
+ ctx := testApex(t, `
+ apex_test {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib_common_test"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib_common_test",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ module := ctx.ModuleForTests("myapex", "android_common_myapex")
+ apexRule := module.Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+
+ if apex, ok := module.Module().(*apexBundle); !ok || !apex.testApex {
+ t.Log("Apex was not a test apex!")
+ t.Fail()
+ }
+ // Ensure that main rule creates an output
+ ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
+
+ // Ensure that apex variant is created for the direct dep
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_core_shared_myapex")
+
+ // Ensure that both direct and indirect deps are copied into apex
+ ensureContains(t, copyCmds, "image.apex/lib64/mylib_common_test.so")
+
+ // Ensure that the platform variant ends with _core_shared
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_core_shared")
+
+ if android.InAnyApex("mylib_common_test") {
+ t.Log("Found mylib_common_test in some apex!")
+ t.Fail()
+ }
+}
+
func TestApexWithTarget(t *testing.T) {
ctx := testApex(t, `
apex {
@@ -944,3 +1102,31 @@
ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_core_shared")
ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_core_shared")
}
+
+func TestApexWithShBinary(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ binaries: ["myscript"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ sh_binary {
+ name: "myscript",
+ src: "mylib.cpp",
+ filename: "myscript.sh",
+ sub_dir: "script",
+ }
+ `)
+
+ apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+
+ ensureContains(t, copyCmds, "image.apex/bin/script/myscript.sh")
+}
diff --git a/apex/key.go b/apex/key.go
index 7e98d2b..5282416 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -19,6 +19,7 @@
"io"
"android/soong/android"
+
"github.com/google/blueprint/proptools"
)
@@ -61,15 +62,7 @@
return m.properties.Installable == nil || proptools.Bool(m.properties.Installable)
}
-func (m *apexKey) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func (m *apexKey) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- if ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild() {
- // Flattened APEXes are not signed
- return
- }
-
m.public_key_file = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Public_key))
m.private_key_file = ctx.Config().ApexKeyDir(ctx).Join(ctx, String(m.properties.Private_key))
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 0e4245e..fc791fe 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -152,7 +152,9 @@
ret.Class = "SHARED_LIBRARIES"
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
fmt.Fprintln(w, "LOCAL_SOONG_TOC :=", library.toc().String())
- fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+ if !library.buildStubs() {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+ }
if len(library.Properties.Overrides) > 0 {
fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES := "+strings.Join(library.Properties.Overrides, " "))
}
diff --git a/cc/binary.go b/cc/binary.go
index a8eb641..4794815 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -317,9 +317,9 @@
builderFlags := flagsToBuilderFlags(flags)
if binary.stripper.needsStrip(ctx) {
- // b/80093681, GNU strip/objcopy bug.
- // Use llvm-{strip,objcopy} when clang lld is used.
- builderFlags.stripUseLlvmStrip = binary.baseLinker.useClangLld(ctx)
+ if ctx.Darwin() {
+ builderFlags.stripUseGnuStrip = true
+ }
strippedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
binary.stripper.strip(ctx, outputFile, strippedOutputFile, builderFlags)
diff --git a/cc/builder.go b/cc/builder.go
index 645b3c2..6e24d56 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -255,7 +255,7 @@
stripKeepSymbols bool
stripKeepMiniDebugInfo bool
stripAddGnuDebuglink bool
- stripUseLlvmStrip bool
+ stripUseGnuStrip bool
protoDeps android.Paths
protoFlags string
@@ -821,8 +821,8 @@
if flags.stripKeepSymbols {
args += " --keep-symbols"
}
- if flags.stripUseLlvmStrip {
- args += " --use-llvm-strip"
+ if flags.stripUseGnuStrip {
+ args += " --use-gnu-strip"
}
ctx.Build(pctx, android.BuildParams{
diff --git a/cc/cc.go b/cc/cc.go
index 4c26e60..7b19e98 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -41,6 +41,7 @@
ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
ctx.BottomUp("version", VersionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
+ ctx.BottomUp("sysprop", SyspropMutator).Parallel()
})
android.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
@@ -62,7 +63,7 @@
ctx.TopDown("sanitize_runtime_deps", sanitizerRuntimeDepsMutator)
ctx.BottomUp("sanitize_runtime", sanitizerRuntimeMutator).Parallel()
- ctx.BottomUp("coverage", coverageLinkingMutator).Parallel()
+ ctx.BottomUp("coverage", coverageMutator).Parallel()
ctx.TopDown("vndk_deps", sabiDepsMutator)
ctx.TopDown("lto_deps", ltoDepsMutator)
@@ -257,6 +258,7 @@
baseModuleName() string
getVndkExtendsModuleName() string
isPgoCompile() bool
+ isNDKStubLibrary() bool
useClangLld(actx ModuleContext) bool
apexName() string
hasStubsVariants() bool
@@ -315,6 +317,7 @@
inData() bool
inSanitizerDir() bool
hostToolPath() android.OptionalPath
+ relativeInstallPath() string
}
type dependencyTag struct {
@@ -347,6 +350,7 @@
linkerFlagsDepTag = dependencyTag{name: "linker flags file"}
dynamicLinkerDepTag = dependencyTag{name: "dynamic linker"}
reuseObjTag = dependencyTag{name: "reuse objects"}
+ staticVariantTag = dependencyTag{name: "static variant"}
ndkStubDepTag = dependencyTag{name: "ndk stub", library: true}
ndkLateStubDepTag = dependencyTag{name: "ndk late stub", library: true}
vndkExtDepTag = dependencyTag{name: "vndk extends", library: true}
@@ -413,6 +417,13 @@
return nil
}
+func (c *Module) RelativeInstallPath() string {
+ if c.installer != nil {
+ return c.installer.relativeInstallPath()
+ }
+ return ""
+}
+
func (c *Module) Init() android.Module {
c.AddProperties(&c.Properties, &c.VendorProperties)
if c.compiler != nil {
@@ -487,6 +498,10 @@
return c.Properties.UseVndk
}
+func (c *Module) isCoverageVariant() bool {
+ return c.coverage.Properties.IsCoverageVariant
+}
+
func (c *Module) isNdk() bool {
return inList(c.Name(), ndkMigratedLibs)
}
@@ -520,6 +535,13 @@
return false
}
+func (c *Module) isNDKStubLibrary() bool {
+ if _, ok := c.compiler.(*stubDecorator); ok {
+ return true
+ }
+ return false
+}
+
func (c *Module) isVndkSp() bool {
if vndkdep := c.vndkdep; vndkdep != nil {
return vndkdep.isVndkSp()
@@ -665,6 +687,10 @@
return ctx.mod.isPgoCompile()
}
+func (ctx *moduleContextImpl) isNDKStubLibrary() bool {
+ return ctx.mod.isNDKStubLibrary()
+}
+
func (ctx *moduleContextImpl) isVndkSp() bool {
return ctx.mod.isVndkSp()
}
@@ -946,7 +972,8 @@
// module is marked with 'bootstrap: true').
if c.HasStubsVariants() &&
android.DirectlyInAnyApex(ctx, ctx.baseModuleName()) &&
- !c.inRecovery() && !c.useVndk() && !c.static() && c.IsStubs() {
+ !c.inRecovery() && !c.useVndk() && !c.static() && !c.isCoverageVariant() &&
+ c.IsStubs() {
c.Properties.HideFromMake = false // unhide
// Note: this is still non-installable
}
@@ -1202,11 +1229,18 @@
{Mutator: "link", Variation: "static"},
}, wholeStaticDepTag, deps.WholeStaticLibs...)
+ syspropImplLibraries := syspropImplLibraries(actx.Config())
+
for _, lib := range deps.StaticLibs {
depTag := staticDepTag
if inList(lib, deps.ReexportStaticLibHeaders) {
depTag = staticExportDepTag
}
+
+ if impl, ok := syspropImplLibraries[lib]; ok {
+ lib = impl
+ }
+
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
}, depTag, lib)
@@ -1244,12 +1278,18 @@
var sharedLibNames []string
for _, lib := range deps.SharedLibs {
- name, version := stubsLibNameAndVersion(lib)
- sharedLibNames = append(sharedLibNames, name)
depTag := sharedDepTag
if inList(lib, deps.ReexportSharedLibHeaders) {
depTag = sharedExportDepTag
}
+
+ if impl, ok := syspropImplLibraries[lib]; ok {
+ lib = impl
+ }
+
+ name, version := stubsLibNameAndVersion(lib)
+ sharedLibNames = append(sharedLibNames, name)
+
addSharedLibDependencies(depTag, name, version)
}
@@ -1370,6 +1410,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
@@ -1527,6 +1568,13 @@
}
}
+ if depTag == staticVariantTag {
+ if _, ok := ccDep.compiler.(libraryInterface); ok {
+ c.staticVariant = ccDep
+ return
+ }
+ }
+
// Extract explicitlyVersioned field from the depTag and reset it inside the struct.
// Otherwise, sharedDepTag and lateSharedDepTag with explicitlyVersioned set to true
// won't be matched to sharedDepTag and lateSharedDepTag.
@@ -1869,9 +1917,6 @@
func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
-func (d *Defaults) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func defaultsFactory() android.Module {
return DefaultsFactory()
}
diff --git a/cc/cc_test.go b/cc/cc_test.go
index dc23620..22ac0d9 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -51,170 +51,12 @@
os.Exit(run())
}
-func gatherRequiredDeps(os android.OsType) string {
- ret := `
- toolchain_library {
- name: "libatomic",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libcompiler_rt-extras",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-arm-android",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-aarch64-android",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-i686-android",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libclang_rt.builtins-x86_64-android",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- toolchain_library {
- name: "libgcc",
- vendor_available: true,
- recovery_available: true,
- src: "",
- }
-
- cc_library {
- name: "libc",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- }
- llndk_library {
- name: "libc",
- symbol_file: "",
- }
- cc_library {
- name: "libm",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- }
- llndk_library {
- name: "libm",
- symbol_file: "",
- }
- cc_library {
- name: "libdl",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- recovery_available: true,
- }
- llndk_library {
- name: "libdl",
- symbol_file: "",
- }
- cc_library {
- name: "libc++_static",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- stl: "none",
- vendor_available: true,
- recovery_available: true,
- }
- cc_library {
- name: "libc++",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- stl: "none",
- vendor_available: true,
- recovery_available: true,
- vndk: {
- enabled: true,
- support_system_process: true,
- },
- }
- cc_library {
- name: "libunwind_llvm",
- no_libgcc: true,
- nocrt: true,
- system_shared_libs: [],
- stl: "none",
- vendor_available: true,
- recovery_available: true,
- }
-
- cc_object {
- name: "crtbegin_so",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtbegin_static",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtend_so",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_object {
- name: "crtend_android",
- recovery_available: true,
- vendor_available: true,
- }
-
- cc_library {
- name: "libprotobuf-cpp-lite",
- }
- `
- if os == android.Fuchsia {
- ret += `
- cc_library {
- name: "libbioniccompat",
- stl: "none",
- }
- cc_library {
- name: "libcompiler_rt",
- stl: "none",
- }
- `
- }
- return ret
-}
-
func createTestContext(t *testing.T, config android.Config, bp string, os android.OsType) *android.TestContext {
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("cc_binary", android.ModuleFactoryAdaptor(BinaryFactory))
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
+ ctx.RegisterModuleType("cc_library_static", android.ModuleFactoryAdaptor(LibraryStaticFactory))
ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory))
ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(ToolchainLibraryFactory))
ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(LlndkLibraryFactory))
@@ -232,7 +74,7 @@
ctx.Register()
// add some modules that are required by the compiler and/or linker
- bp = bp + gatherRequiredDeps(os)
+ bp = bp + GatherRequiredDepsForTest(os)
ctx.MockFileSystem(map[string][]byte{
"Android.bp": []byte(bp),
@@ -1966,3 +1808,43 @@
}
}
}
+
+func TestStaticDepsOrderWithStubs(t *testing.T) {
+ ctx := testCc(t, `
+ cc_binary {
+ name: "mybin",
+ srcs: ["foo.c"],
+ static_libs: ["libB"],
+ static_executable: true,
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libB",
+ srcs: ["foo.c"],
+ shared_libs: ["libC"],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libC",
+ srcs: ["foo.c"],
+ stl: "none",
+ stubs: {
+ versions: ["1"],
+ },
+ }`)
+
+ mybin := ctx.ModuleForTests("mybin", "android_arm64_armv8-a_core").Module().(*Module)
+ actual := mybin.depsInLinkOrder
+ expected := getOutputPaths(ctx, "android_arm64_armv8-a_core_static", []string{"libB", "libC"})
+
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf("staticDeps orderings were not propagated correctly"+
+ "\nactual: %v"+
+ "\nexpected: %v",
+ actual,
+ expected,
+ )
+ }
+}
diff --git a/cc/compiler.go b/cc/compiler.go
index fbe10b5..0aee0bd 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -250,8 +250,8 @@
return false
}
-func addToModuleList(ctx ModuleContext, list string, module string) {
- getNamedMapForConfig(ctx.Config(), list).Store(module, true)
+func addToModuleList(ctx ModuleContext, key android.OnceKey, module string) {
+ getNamedMapForConfig(ctx.Config(), key).Store(module, true)
}
// Create a Flags struct that collects the compile flags from global values,
@@ -503,10 +503,10 @@
if len(compiler.Properties.Srcs) > 0 {
module := ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
if inList("-Wno-error", flags.CFlags) || inList("-Wno-error", flags.CppFlags) {
- addToModuleList(ctx, modulesUsingWnoError, module)
+ addToModuleList(ctx, modulesUsingWnoErrorKey, module)
} else if !inList("-Werror", flags.CFlags) && !inList("-Werror", flags.CppFlags) {
if warningsAreAllowed(ctx.ModuleDir()) {
- addToModuleList(ctx, modulesAddedWall, module)
+ addToModuleList(ctx, modulesAddedWallKey, module)
flags.CFlags = append([]string{"-Wall"}, flags.CFlags...)
} else {
flags.CFlags = append([]string{"-Wall", "-Werror"}, flags.CFlags...)
diff --git a/cc/coverage.go b/cc/coverage.go
index 391b118..79f7d7d 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -15,13 +15,16 @@
package cc
import (
+ "strconv"
+
"android/soong/android"
)
type CoverageProperties struct {
Native_coverage *bool
- CoverageEnabled bool `blueprint:"mutated"`
+ CoverageEnabled bool `blueprint:"mutated"`
+ IsCoverageVariant bool `blueprint:"mutated"`
}
type coverage struct {
@@ -93,27 +96,54 @@
return flags
}
-func coverageLinkingMutator(mctx android.BottomUpMutatorContext) {
- if c, ok := mctx.Module().(*Module); ok && c.coverage != nil {
- var enabled bool
+func coverageMutator(mctx android.BottomUpMutatorContext) {
+ // Coverage is disabled globally
+ if !mctx.DeviceConfig().NativeCoverageEnabled() {
+ return
+ }
- if !mctx.DeviceConfig().NativeCoverageEnabled() {
- // Coverage is disabled globally
- } else if mctx.Host() {
+ if c, ok := mctx.Module().(*Module); ok {
+ var needCoverageVariant bool
+ var needCoverageBuild bool
+
+ if mctx.Host() {
// TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
// Just turn off for now.
- } else if c.coverage.Properties.Native_coverage != nil {
- enabled = *c.coverage.Properties.Native_coverage
- } else {
- enabled = mctx.DeviceConfig().CoverageEnabledForPath(mctx.ModuleDir())
+ } else if c.useVndk() || c.hasVendorVariant() {
+ // Do not enable coverage for VNDK libraries
+ } else if c.isNDKStubLibrary() {
+ // Do not enable coverage for NDK stub libraries
+ } else if c.coverage != nil {
+ // Check if Native_coverage is set to false. This property defaults to true.
+ needCoverageVariant = BoolDefault(c.coverage.Properties.Native_coverage, true)
+
+ if sdk_version := String(c.Properties.Sdk_version); sdk_version != "current" {
+ // Native coverage is not supported for SDK versions < 23
+ if fromApi, err := strconv.Atoi(sdk_version); err == nil && fromApi < 23 {
+ needCoverageVariant = false
+ }
+ }
+
+ if needCoverageVariant {
+ // Coverage variant is actually built with coverage if enabled for its module path
+ needCoverageBuild = mctx.DeviceConfig().CoverageEnabledForPath(mctx.ModuleDir())
+ }
}
- if enabled {
- // Create a variation so that we don't need to recompile objects
- // when turning on or off coverage. We'll still relink the necessary
- // binaries, since we don't know which ones those are until later.
- m := mctx.CreateLocalVariations("cov")
- m[0].(*Module).coverage.Properties.CoverageEnabled = true
+ if needCoverageVariant {
+ m := mctx.CreateVariations("", "cov")
+
+ // Setup the non-coverage version and set HideFromMake and
+ // PreventInstall to true.
+ m[0].(*Module).coverage.Properties.CoverageEnabled = false
+ m[0].(*Module).coverage.Properties.IsCoverageVariant = false
+ m[0].(*Module).Properties.HideFromMake = true
+ m[0].(*Module).Properties.PreventInstall = true
+
+ // The coverage-enabled version inherits HideFromMake,
+ // PreventInstall from the original module.
+ m[1].(*Module).coverage.Properties.CoverageEnabled = needCoverageBuild
+ m[1].(*Module).coverage.Properties.IsCoverageVariant = true
}
}
}
diff --git a/cc/gen.go b/cc/gen.go
index c3088f4..0c3d089 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -56,10 +56,11 @@
sysprop = pctx.AndroidStaticRule("sysprop",
blueprint.RuleParams{
- Command: "$syspropCmd --header-output-dir=$headerOutDir --source-output-dir=$srcOutDir --include-name=$includeName $in",
+ Command: "$syspropCmd --header-dir=$headerOutDir --system-header-dir=$systemOutDir " +
+ "--source-dir=$srcOutDir --include-name=$includeName $in",
CommandDeps: []string{"$syspropCmd"},
},
- "headerOutDir", "srcOutDir", "includeName")
+ "headerOutDir", "systemOutDir", "srcOutDir", "includeName")
windmc = pctx.AndroidStaticRule("windmc",
blueprint.RuleParams{
@@ -114,6 +115,7 @@
func genSysprop(ctx android.ModuleContext, syspropFile android.Path) (android.Path, android.Path) {
headerFile := android.PathForModuleGen(ctx, "sysprop", "include", syspropFile.Rel()+".h")
+ systemHeaderFile := android.PathForModuleGen(ctx, "sysprop/system", "include", syspropFile.Rel()+".h")
cppFile := android.PathForModuleGen(ctx, "sysprop", syspropFile.Rel()+".cpp")
ctx.Build(pctx, android.BuildParams{
@@ -124,6 +126,7 @@
Input: syspropFile,
Args: map[string]string{
"headerOutDir": filepath.Dir(headerFile.String()),
+ "systemOutDir": filepath.Dir(systemHeaderFile.String()),
"srcOutDir": filepath.Dir(cppFile.String()),
"includeName": syspropFile.Rel() + ".h",
},
diff --git a/cc/gen_stub_libs.py b/cc/gen_stub_libs.py
index 4906ea2..81bc398 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/gen_stub_libs.py
@@ -119,9 +119,12 @@
return True
if 'platform-only' in version.tags:
return True
- if 'vndk' in version.tags and not vndk:
- return True
- if 'apex' in version.tags and not apex:
+
+ no_vndk_no_apex = 'vndk' not in version.tags and 'apex' not in version.tags
+ keep = no_vndk_no_apex or \
+ ('vndk' in version.tags and vndk) or \
+ ('apex' in version.tags and apex)
+ if not keep:
return True
if not symbol_in_arch(version.tags, arch):
return True
@@ -132,9 +135,11 @@
def should_omit_symbol(symbol, arch, api, vndk, apex):
"""Returns True if the symbol should be omitted."""
- if not vndk and 'vndk' in symbol.tags:
- return True
- if not apex and 'apex' in symbol.tags:
+ no_vndk_no_apex = 'vndk' not in symbol.tags and 'apex' not in symbol.tags
+ keep = no_vndk_no_apex or \
+ ('vndk' in symbol.tags and vndk) or \
+ ('apex' in symbol.tags and apex)
+ if not keep:
return True
if not symbol_in_arch(symbol.tags, arch):
return True
diff --git a/cc/installer.go b/cc/installer.go
index 33f29f2..bd8f9e7 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -73,7 +73,7 @@
dir = filepath.Join(dir, "vendor")
}
return android.PathForModuleInstall(ctx, dir, installer.subDir,
- String(installer.Properties.Relative_install_path), installer.relative)
+ installer.relativeInstallPath(), installer.relative)
}
func (installer *baseInstaller) install(ctx ModuleContext, file android.Path) {
@@ -91,3 +91,7 @@
func (installer *baseInstaller) hostToolPath() android.OptionalPath {
return android.OptionalPath{}
}
+
+func (installer *baseInstaller) relativeInstallPath() string {
+ return String(installer.Properties.Relative_install_path)
+}
diff --git a/cc/library.go b/cc/library.go
index 13acfae..a48b45d 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -67,6 +67,11 @@
Export_proto_headers *bool
}
+ Sysprop struct {
+ // Whether platform owns this sysprop library.
+ Platform *bool
+ }
+
Static_ndk_lib *bool
Stubs struct {
@@ -686,9 +691,9 @@
TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
if library.stripper.needsStrip(ctx) {
- // b/80093681, GNU strip/objcopy bug.
- // Use llvm-{strip,objcopy} when clang lld is used.
- builderFlags.stripUseLlvmStrip = library.baseLinker.useClangLld(ctx)
+ if ctx.Darwin() {
+ builderFlags.stripUseGnuStrip = true
+ }
strippedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
library.stripper.strip(ctx, outputFile, strippedOutputFile, builderFlags)
@@ -836,9 +841,27 @@
}
if library.baseCompiler.hasSrcExt(".sysprop") {
- flags := []string{
+ internalFlags := []string{
"-I" + android.PathForModuleGen(ctx, "sysprop", "include").String(),
}
+ systemFlags := []string{
+ "-I" + android.PathForModuleGen(ctx, "sysprop/system", "include").String(),
+ }
+
+ flags := internalFlags
+
+ if library.Properties.Sysprop.Platform != nil {
+ isProduct := ctx.ProductSpecific() && !ctx.useVndk()
+ isVendor := ctx.useVndk()
+ isOwnerPlatform := Bool(library.Properties.Sysprop.Platform)
+
+ useSystem := isProduct || (isOwnerPlatform == isVendor)
+
+ if useSystem {
+ flags = systemFlags
+ }
+ }
+
library.reexportFlags(flags)
library.reexportDeps(library.baseCompiler.pathDeps)
library.reuseExportedFlags = append(library.reuseExportedFlags, flags...)
@@ -968,8 +991,10 @@
return library.MutatedProperties.StubsVersion
}
+var versioningMacroNamesListKey = android.NewOnceKey("versioningMacroNamesList")
+
func versioningMacroNamesList(config android.Config) *map[string]string {
- return config.Once("versioningMacroNamesList", func() interface{} {
+ return config.Once(versioningMacroNamesListKey, func() interface{} {
m := make(map[string]string)
return &m
}).(*map[string]string)
@@ -1030,6 +1055,9 @@
sharedCompiler.baseCompiler.Properties.Srcs
sharedCompiler.baseCompiler.Properties.Srcs = nil
sharedCompiler.baseCompiler.Properties.Generated_sources = nil
+ } else {
+ // This dep is just to reference static variant from shared variant
+ mctx.AddInterVariantDependency(staticVariantTag, shared, static)
}
}
}
@@ -1059,9 +1087,11 @@
}
}
+var stubVersionsKey = android.NewOnceKey("stubVersions")
+
// maps a module name to the list of stubs versions available for the module
func stubsVersionsFor(config android.Config) map[string][]string {
- return config.Once("stubVersions", func() interface{} {
+ return config.Once(stubVersionsKey, func() interface{} {
return make(map[string][]string)
}).(map[string][]string)
}
diff --git a/cc/linker.go b/cc/linker.go
index dbdcd57..649185a 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -225,14 +225,9 @@
}
if ctx.toolchain().Bionic() {
- // Allow individual projects to opt out of libcrt,builtins
- // b/117565638
+ // libclang_rt.builtins, libgcc and libatomic have to be last on the command line
if !Bool(linker.Properties.No_libcrt) {
- // libclang_rt.builtins, libgcc and libatomic have to be last on the command line
- // TODO: Also enable for libc and libm
- if ctx.ModuleName() != "libc" && ctx.ModuleName() != "libm" {
- deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
- }
+ deps.LateStaticLibs = append(deps.LateStaticLibs, config.BuiltinsRuntimeLibrary(ctx.toolchain()))
}
deps.LateStaticLibs = append(deps.LateStaticLibs, "libatomic")
diff --git a/cc/makevars.go b/cc/makevars.go
index 32674a9..4a9ade2 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -24,24 +24,24 @@
"android/soong/cc/config"
)
-const (
- modulesAddedWall = "ModulesAddedWall"
- modulesUsingWnoError = "ModulesUsingWnoError"
- modulesMissingProfileFile = "ModulesMissingProfileFile"
+var (
+ modulesAddedWallKey = android.NewOnceKey("ModulesAddedWall")
+ modulesUsingWnoErrorKey = android.NewOnceKey("ModulesUsingWnoError")
+ modulesMissingProfileFileKey = android.NewOnceKey("ModulesMissingProfileFile")
)
func init() {
android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
}
-func getNamedMapForConfig(config android.Config, name string) *sync.Map {
- return config.Once(name, func() interface{} {
+func getNamedMapForConfig(config android.Config, key android.OnceKey) *sync.Map {
+ return config.Once(key, func() interface{} {
return &sync.Map{}
}).(*sync.Map)
}
-func makeStringOfKeys(ctx android.MakeVarsContext, setName string) string {
- set := getNamedMapForConfig(ctx.Config(), setName)
+func makeStringOfKeys(ctx android.MakeVarsContext, key android.OnceKey) string {
+ set := getNamedMapForConfig(ctx.Config(), key)
keys := []string{}
set.Range(func(key interface{}, value interface{}) bool {
keys = append(keys, key.(string))
@@ -100,7 +100,7 @@
// Filter vendor_public_library that are exported to make
exportedVendorPublicLibraries := []string{}
- ctx.SingletonContext().VisitAllModules(func(module android.Module) {
+ ctx.VisitAllModules(func(module android.Module) {
if ccModule, ok := module.(*Module); ok {
baseName := ccModule.BaseModuleName()
if inList(baseName, vendorPublicLibraries) && module.ExportedToMake() {
@@ -117,9 +117,9 @@
ctx.Strict("LSDUMP_PATHS", strings.Join(lsdumpPaths, " "))
ctx.Strict("ANDROID_WARNING_ALLOWED_PROJECTS", makeStringOfWarningAllowedProjects())
- ctx.Strict("SOONG_MODULES_ADDED_WALL", makeStringOfKeys(ctx, modulesAddedWall))
- ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoError))
- ctx.Strict("SOONG_MODULES_MISSING_PGO_PROFILE_FILE", makeStringOfKeys(ctx, modulesMissingProfileFile))
+ ctx.Strict("SOONG_MODULES_ADDED_WALL", makeStringOfKeys(ctx, modulesAddedWallKey))
+ ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoErrorKey))
+ ctx.Strict("SOONG_MODULES_MISSING_PGO_PROFILE_FILE", makeStringOfKeys(ctx, modulesMissingProfileFileKey))
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
@@ -178,14 +178,6 @@
makeVarsToolchain(ctx, "2ND_", hostTargets[1])
}
- crossTargets := ctx.Config().Targets[android.Windows]
- if len(crossTargets) > 0 {
- makeVarsToolchain(ctx, "", crossTargets[0])
- if len(crossTargets) > 1 {
- makeVarsToolchain(ctx, "2ND_", crossTargets[1])
- }
- }
-
deviceTargets := ctx.Config().Targets[android.Android]
makeVarsToolchain(ctx, "", deviceTargets[0])
if len(deviceTargets) > 1 {
@@ -199,8 +191,6 @@
switch target.Os.Class {
case android.Host:
typePrefix = "HOST_"
- case android.HostCross:
- typePrefix = "HOST_CROSS_"
case android.Device:
typePrefix = "TARGET_"
}
@@ -301,10 +291,6 @@
ctx.Strict(makePrefix+"STRIP", gccCmd(toolchain, "strip"))
}
- if target.Os == android.Windows {
- ctx.Strict(makePrefix+"OBJDUMP", gccCmd(toolchain, "objdump"))
- }
-
if target.Os.Class == android.Device {
ctx.Strict(makePrefix+"OBJCOPY", gccCmd(toolchain, "objcopy"))
ctx.Strict(makePrefix+"LD", gccCmd(toolchain, "ld"))
@@ -313,7 +299,7 @@
ctx.Strict(makePrefix+"TOOLS_PREFIX", gccCmd(toolchain, ""))
}
- if target.Os.Class == android.Host || target.Os.Class == android.HostCross {
+ if target.Os.Class == android.Host {
ctx.Strict(makePrefix+"AVAILABLE_LIBRARIES", strings.Join(toolchain.AvailableLibraries(), " "))
}
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 504a6a0..c0ce9c3 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -93,9 +93,6 @@
licensePath android.ModuleSrcPath
}
-func (m *headerModule) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func getHeaderInstallDir(ctx android.ModuleContext, header android.Path, from string,
to string) android.OutputPath {
// Output path is the sysroot base + "usr/include" + to directory + directory component
@@ -210,9 +207,6 @@
licensePath android.ModuleSrcPath
}
-func (m *versionedHeaderModule) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func (m *versionedHeaderModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if String(m.properties.License) == "" {
ctx.PropertyErrorf("license", "field is required")
@@ -335,9 +329,6 @@
licensePath android.ModuleSrcPath
}
-func (m *preprocessedHeadersModule) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func (m *preprocessedHeadersModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if String(m.properties.License) == "" {
ctx.PropertyErrorf("license", "field is required")
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 1b09f88..3ae4452 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -53,6 +53,7 @@
"OpenMAXAL",
"OpenSLES",
"stdc++",
+ "sync",
"vulkan",
"z",
}
diff --git a/cc/pgo.go b/cc/pgo.go
index a341ab9..9363916 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -36,7 +36,8 @@
}
)
-const pgoProfileProjectsConfigKey = "PgoProfileProjects"
+var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects")
+
const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp"
const profileSamplingFlag = "-gline-tables-only"
const profileUseInstrumentFormat = "-fprofile-use=%s"
@@ -49,7 +50,7 @@
}
func recordMissingProfileFile(ctx BaseModuleContext, missing string) {
- getNamedMapForConfig(ctx.Config(), modulesMissingProfileFile).Store(missing, true)
+ getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
}
type PgoProperties struct {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index ebb638e..7297718 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -370,8 +370,8 @@
sanitize.Properties.SanitizerEnabled = true
}
- // Disable Scudo if ASan or TSan is enabled.
- if Bool(s.Address) || Bool(s.Thread) || Bool(s.Hwaddress) {
+ // Disable Scudo if ASan or TSan is enabled, or if it's disabled globally.
+ if Bool(s.Address) || Bool(s.Thread) || Bool(s.Hwaddress) || ctx.Config().DisableScudo() {
s.Scudo = nil
}
@@ -444,7 +444,11 @@
flags.LdFlags = append(flags.LdFlags, "-Wl,--no-as-needed")
} else {
flags.CFlags = append(flags.CFlags, "-mllvm", "-asan-globals=0")
- flags.DynamicLinker = "/system/bin/linker_asan"
+ if ctx.bootstrap() {
+ flags.DynamicLinker = "/system/bin/bootstrap/linker_asan"
+ } else {
+ flags.DynamicLinker = "/system/bin/linker_asan"
+ }
if flags.Toolchain.Is64Bit() {
flags.DynamicLinker += "64"
}
@@ -662,6 +666,14 @@
}
return true
})
+ } else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
+ // If an APEX module includes a lib which is enabled for a sanitizer T, then
+ // the APEX module is also enabled for the same sanitizer type.
+ mctx.VisitDirectDeps(func(child android.Module) {
+ if c, ok := child.(*Module); ok && c.sanitize.isSanitizerEnabled(t) {
+ sanitizeable.EnableSanitizer(t.name())
+ }
+ })
}
}
}
@@ -844,6 +856,7 @@
type Sanitizeable interface {
android.Module
IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool
+ EnableSanitizer(sanitizerName string)
}
// Create sanitized variants for modules that need them
@@ -954,20 +967,26 @@
}
}
+var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs")
+
func cfiStaticLibs(config android.Config) *[]string {
- return config.Once("cfiStaticLibs", func() interface{} {
+ return config.Once(cfiStaticLibsKey, func() interface{} {
return &[]string{}
}).(*[]string)
}
+var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs")
+
func hwasanStaticLibs(config android.Config) *[]string {
- return config.Once("hwasanStaticLibs", func() interface{} {
+ return config.Once(hwasanStaticLibsKey, func() interface{} {
return &[]string{}
}).(*[]string)
}
+var hwasanVendorStaticLibsKey = android.NewOnceKey("hwasanVendorStaticLibs")
+
func hwasanVendorStaticLibs(config android.Config) *[]string {
- return config.Once("hwasanVendorStaticLibs", func() interface{} {
+ return config.Once(hwasanVendorStaticLibsKey, func() interface{} {
return &[]string{}
}).(*[]string)
}
diff --git a/cc/sysprop.go b/cc/sysprop.go
new file mode 100644
index 0000000..656f79f
--- /dev/null
+++ b/cc/sysprop.go
@@ -0,0 +1,47 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "sync"
+
+ "android/soong/android"
+)
+
+type syspropLibraryInterface interface {
+ CcModuleName() string
+}
+
+var (
+ syspropImplLibrariesKey = android.NewOnceKey("syspropImplLibirares")
+ syspropImplLibrariesLock sync.Mutex
+)
+
+func syspropImplLibraries(config android.Config) map[string]string {
+ return config.Once(syspropImplLibrariesKey, func() interface{} {
+ return make(map[string]string)
+ }).(map[string]string)
+}
+
+// gather list of sysprop libraries
+func SyspropMutator(mctx android.BottomUpMutatorContext) {
+ if m, ok := mctx.Module().(syspropLibraryInterface); ok {
+ syspropImplLibraries := syspropImplLibraries(mctx.Config())
+ syspropImplLibrariesLock.Lock()
+ defer syspropImplLibrariesLock.Unlock()
+
+ syspropImplLibraries[mctx.ModuleName()] = m.CcModuleName()
+ }
+}
diff --git a/cc/test_gen_stub_libs.py b/cc/test_gen_stub_libs.py
index 594c1bc..2ee9886 100755
--- a/cc/test_gen_stub_libs.py
+++ b/cc/test_gen_stub_libs.py
@@ -751,6 +751,8 @@
wibble;
wizzes; # vndk
waggle; # apex
+ bubble; # apex vndk
+ duddle; # vndk apex
} VERSION_2;
VERSION_5 { # versioned=14
@@ -771,6 +773,8 @@
void qux() {}
void wibble() {}
void waggle() {}
+ void bubble() {}
+ void duddle() {}
void wobble() {}
""")
self.assertEqual(expected_src, src_file.getvalue())
@@ -788,6 +792,8 @@
global:
wibble;
waggle;
+ bubble;
+ duddle;
} VERSION_2;
""")
self.assertEqual(expected_version, version_file.getvalue())
diff --git a/cc/testing.go b/cc/testing.go
new file mode 100644
index 0000000..b3b2756
--- /dev/null
+++ b/cc/testing.go
@@ -0,0 +1,188 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package cc
+
+import (
+ "android/soong/android"
+)
+
+func GatherRequiredDepsForTest(os android.OsType) string {
+ ret := `
+ toolchain_library {
+ name: "libatomic",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libcompiler_rt-extras",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.builtins-arm-android",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.builtins-aarch64-android",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.builtins-i686-android",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.builtins-x86_64-android",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libgcc",
+ vendor_available: true,
+ recovery_available: true,
+ src: "",
+ }
+
+ cc_library {
+ name: "libbase",
+ no_libgcc: true,
+ nocrt: true,
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ }
+ }
+ cc_library {
+ name: "libc",
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
+ recovery_available: true,
+ }
+ llndk_library {
+ name: "libc",
+ symbol_file: "",
+ }
+ cc_library {
+ name: "libm",
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
+ recovery_available: true,
+ }
+ llndk_library {
+ name: "libm",
+ symbol_file: "",
+ }
+ cc_library {
+ name: "libdl",
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
+ recovery_available: true,
+ }
+ llndk_library {
+ name: "libdl",
+ symbol_file: "",
+ }
+ cc_library {
+ name: "libc++_static",
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ vendor_available: true,
+ recovery_available: true,
+ }
+ cc_library {
+ name: "libc++",
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ vendor_available: true,
+ recovery_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ }
+ cc_library {
+ name: "libunwind_llvm",
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ vendor_available: true,
+ recovery_available: true,
+ }
+
+ cc_object {
+ name: "crtbegin_so",
+ recovery_available: true,
+ vendor_available: true,
+ }
+
+ cc_object {
+ name: "crtbegin_static",
+ recovery_available: true,
+ vendor_available: true,
+ }
+
+ cc_object {
+ name: "crtend_so",
+ recovery_available: true,
+ vendor_available: true,
+ }
+
+ cc_object {
+ name: "crtend_android",
+ recovery_available: true,
+ vendor_available: true,
+ }
+
+ cc_library {
+ name: "libprotobuf-cpp-lite",
+ }
+ `
+ if os == android.Fuchsia {
+ ret += `
+ cc_library {
+ name: "libbioniccompat",
+ stl: "none",
+ }
+ cc_library {
+ name: "libcompiler_rt",
+ stl: "none",
+ }
+ `
+ }
+ return ret
+}
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 6a3d579..330c5dd 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -172,7 +172,8 @@
stat := &status.Status{}
defer stat.Finish()
- stat.AddOutput(terminal.NewStatusOutput(writer, ""))
+ stat.AddOutput(terminal.NewStatusOutput(writer, "",
+ build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
var failures failureCount
stat.AddOutput(&failures)
@@ -389,7 +390,8 @@
Thread: mpctx.Tracer.NewThread(product),
Status: &status.Status{},
}}
- ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, ""))
+ ctx.Status.AddOutput(terminal.NewStatusOutput(ctx.Writer, "",
+ build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
config := build.NewConfig(ctx, flag.Args()...)
config.Environment().Set("OUT_DIR", outDir)
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index a4c6898..1f6002e 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -75,6 +75,10 @@
bootstrap.Main(ctx.Context, configuration, configuration.ConfigFileName, configuration.ProductVariablesFileName)
if docFile != "" {
- writeDocs(ctx, docFile)
+ err := writeDocs(ctx, docFile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "%s", err)
+ os.Exit(1)
+ }
}
}
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index a6686c0..8f86b33 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -19,18 +19,33 @@
"bytes"
"html/template"
"io/ioutil"
+ "reflect"
+ "sort"
"github.com/google/blueprint/bootstrap"
+ "github.com/google/blueprint/bootstrap/bpdoc"
)
func writeDocs(ctx *android.Context, filename string) error {
- moduleTypeList, err := bootstrap.ModuleTypeDocs(ctx.Context)
+ moduleTypeFactories := android.ModuleTypeFactories()
+ bpModuleTypeFactories := make(map[string]reflect.Value)
+ for moduleType, factory := range moduleTypeFactories {
+ bpModuleTypeFactories[moduleType] = reflect.ValueOf(factory)
+ }
+
+ packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
if err != nil {
return err
}
buf := &bytes.Buffer{}
+ var moduleTypeList []*bpdoc.ModuleType
+ for _, pkg := range packages {
+ moduleTypeList = append(moduleTypeList, pkg.ModuleTypes...)
+ }
+ sort.Slice(moduleTypeList, func(i, j int) bool { return moduleTypeList[i].Name < moduleTypeList[j].Name })
+
unique := 0
tmpl, err := template.New("file").Funcs(map[string]interface{}{
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 0380368..d6999c5 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -78,7 +78,8 @@
stat := &status.Status{}
defer stat.Finish()
- stat.AddOutput(terminal.NewStatusOutput(writer, os.Getenv("NINJA_STATUS")))
+ stat.AddOutput(terminal.NewStatusOutput(writer, os.Getenv("NINJA_STATUS"),
+ build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD")))
stat.AddOutput(trace.StatusTracer())
build.SetupSignals(log, cancel, func() {
diff --git a/dexpreopt/Android.bp b/dexpreopt/Android.bp
index b832529..c5f24e2 100644
--- a/dexpreopt/Android.bp
+++ b/dexpreopt/Android.bp
@@ -4,12 +4,12 @@
srcs: [
"config.go",
"dexpreopt.go",
- "script.go",
],
testSrcs: [
"dexpreopt_test.go",
],
deps: [
"blueprint-pathtools",
+ "soong-android",
],
-}
\ No newline at end of file
+}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 3725146..c7f0638 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -17,6 +17,8 @@
import (
"encoding/json"
"io/ioutil"
+
+ "android/soong/android"
)
// GlobalConfig stores the configuration for dex preopting set by the product
@@ -46,7 +48,8 @@
DefaultCompilerFilter string // default compiler filter to pass to dex2oat, overridden by --compiler-filter= in module-specific dex2oat flags
SystemServerCompilerFilter string // default compiler filter to pass to dex2oat for system server jars
- GenerateDMFiles bool // generate Dex Metadata files
+ GenerateDMFiles bool // generate Dex Metadata files
+ NeverAllowStripping bool // whether stripping should not be done - used as build time check to make sure dex files are always available
NoDebugInfo bool // don't generate debug info by default
AlwaysSystemServerDebugInfo bool // always generate mini debug info for system server modules (overrides NoDebugInfo=true)
@@ -66,9 +69,9 @@
EmptyDirectory string // path to an empty directory
- DefaultDexPreoptImageLocation map[string]string // default boot image location for each architecture
- CpuVariant map[string]string // cpu variant for each architecture
- InstructionSetFeatures map[string]string // instruction set for each architecture
+ DefaultDexPreoptImage map[android.ArchType]string // default boot image location for each architecture
+ CpuVariant map[android.ArchType]string // cpu variant for each architecture
+ InstructionSetFeatures map[android.ArchType]string // instruction set for each architecture
Tools Tools // paths to tools possibly used by the generated commands
}
@@ -91,7 +94,6 @@
DexLocation string // dex location on device
BuildPath string
DexPath string
- UseEmbeddedDex bool
UncompressedDex bool
HasApkLibraries bool
PreoptFlags []string
@@ -104,8 +106,8 @@
UsesLibraries []string
LibraryPaths map[string]string
- Archs []string
- DexPreoptImageLocation string
+ Archs []android.ArchType
+ DexPreoptImages []string
PreoptExtractedApk bool // Overrides OnlyPreoptModules
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index f316be4..68bd3ea 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -39,6 +39,8 @@
"path/filepath"
"strings"
+ "android/soong/android"
+
"github.com/google/blueprint/pathtools"
)
@@ -47,7 +49,7 @@
// GenerateStripRule generates a set of commands that will take an APK or JAR as an input and strip the dex files if
// they are no longer necessary after preopting.
-func GenerateStripRule(global GlobalConfig, module ModuleConfig) (rule *Rule, err error) {
+func GenerateStripRule(global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) {
defer func() {
if r := recover(); r != nil {
if e, ok := r.(error); ok {
@@ -61,11 +63,14 @@
tools := global.Tools
- rule = &Rule{}
+ rule = android.NewRuleBuilder()
strip := shouldStripDex(module, global)
if strip {
+ if global.NeverAllowStripping {
+ panic(fmt.Errorf("Stripping requested on %q, though the product does not allow it", module.DexLocation))
+ }
// Only strips if the dex files are not already uncompressed
rule.Command().
Textf(`if (zipinfo %s '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then`, module.StripInputPath).
@@ -81,7 +86,7 @@
// GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
// ModuleConfig. The produced files and their install locations will be available through rule.Installs().
-func GenerateDexpreoptRule(global GlobalConfig, module ModuleConfig) (rule *Rule, err error) {
+func GenerateDexpreoptRule(global GlobalConfig, module ModuleConfig) (rule *android.RuleBuilder, err error) {
defer func() {
if r := recover(); r != nil {
if e, ok := r.(error); ok {
@@ -93,7 +98,7 @@
}
}()
- rule = &Rule{}
+ rule = android.NewRuleBuilder()
generateProfile := module.ProfileClassListing != "" && !global.DisableGenerateProfile
@@ -111,12 +116,9 @@
generateDM := shouldGenerateDM(module, global)
- for _, arch := range module.Archs {
- imageLocation := module.DexPreoptImageLocation
- if imageLocation == "" {
- imageLocation = global.DefaultDexPreoptImageLocation[arch]
- }
- dexpreoptCommand(global, module, rule, profile, arch, imageLocation, appImage, generateDM)
+ for i, arch := range module.Archs {
+ image := module.DexPreoptImages[i]
+ dexpreoptCommand(global, module, rule, arch, profile, image, appImage, generateDM)
}
}
}
@@ -141,7 +143,7 @@
return false
}
-func profileCommand(global GlobalConfig, module ModuleConfig, rule *Rule) string {
+func profileCommand(global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder) string {
profilePath := filepath.Join(filepath.Dir(module.BuildPath), "profile.prof")
profileInstalledPath := module.DexLocation + ".prof"
@@ -178,8 +180,8 @@
return profilePath
}
-func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *Rule, profile, arch, bootImageLocation string,
- appImage, generateDM bool) {
+func dexpreoptCommand(global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder,
+ arch android.ArchType, profile, bootImage string, appImage, generateDM bool) {
// HACK: make soname in Soong-generated .odex files match Make.
base := filepath.Base(module.DexLocation)
@@ -193,7 +195,7 @@
return filepath.Join(
filepath.Dir(path),
"oat",
- arch,
+ arch.String(),
pathtools.ReplaceExtension(filepath.Base(path), "odex"))
}
@@ -211,11 +213,11 @@
invocationPath := pathtools.ReplaceExtension(odexPath, "invocation")
- // bootImageLocation is $OUT/dex_bootjars/system/framework/boot.art, but dex2oat actually reads
- // $OUT/dex_bootjars/system/framework/arm64/boot.art
- var bootImagePath string
- if bootImageLocation != "" {
- bootImagePath = filepath.Join(filepath.Dir(bootImageLocation), arch, filepath.Base(bootImageLocation))
+ // bootImage is .../dex_bootjars/system/framework/arm64/boot.art, but dex2oat wants
+ // .../dex_bootjars/system/framework/boot.art on the command line
+ var bootImageLocation string
+ if bootImage != "" {
+ bootImageLocation = PathToLocation(bootImage, arch)
}
// Lists of used and optional libraries from the build config to be verified against the manifest in the APK
@@ -323,13 +325,13 @@
Flag("--runtime-arg").FlagWithArg("-Xbootclasspath-locations:", bcp_locations).
Flag("${class_loader_context_arg}").
Flag("${stored_class_loader_context_arg}").
- FlagWithArg("--boot-image=", bootImageLocation).Implicit(bootImagePath).
+ FlagWithArg("--boot-image=", bootImageLocation).Implicit(bootImage).
FlagWithInput("--dex-file=", module.DexPath).
FlagWithArg("--dex-location=", module.DexLocation).
FlagWithOutput("--oat-file=", odexPath).ImplicitOutput(vdexPath).
// Pass an empty directory, dex2oat shouldn't be reading arbitrary files
FlagWithArg("--android-root=", global.EmptyDirectory).
- FlagWithArg("--instruction-set=", arch).
+ FlagWithArg("--instruction-set=", arch.String()).
FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]).
FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]).
Flag("--no-generate-debug-info").
@@ -497,7 +499,7 @@
contains(module.PreoptFlags, "--compiler-filter=verify")
}
-func odexOnSystemOther(module ModuleConfig, global GlobalConfig) bool {
+func OdexOnSystemOtherByName(name string, dexLocation string, global GlobalConfig) bool {
if !global.HasSystemOther {
return false
}
@@ -506,12 +508,12 @@
return false
}
- if contains(global.SpeedApps, module.Name) || contains(global.SystemServerApps, module.Name) {
+ if contains(global.SpeedApps, name) || contains(global.SystemServerApps, name) {
return false
}
for _, f := range global.PatternsOnSystemOther {
- if makefileMatch(filepath.Join(SystemPartition, f), module.DexLocation) {
+ if makefileMatch(filepath.Join(SystemPartition, f), dexLocation) {
return true
}
}
@@ -519,6 +521,19 @@
return false
}
+func odexOnSystemOther(module ModuleConfig, global GlobalConfig) bool {
+ return OdexOnSystemOtherByName(module.Name, module.DexLocation, global)
+}
+
+// PathToLocation converts .../system/framework/arm64/boot.art to .../system/framework/boot.art
+func PathToLocation(path string, arch android.ArchType) string {
+ pathArch := filepath.Base(filepath.Dir(path))
+ if pathArch != arch.String() {
+ panic(fmt.Errorf("last directory in %q must be %q", path, arch.String()))
+ }
+ return filepath.Join(filepath.Dir(filepath.Dir(path)), filepath.Base(path))
+}
+
func pathForLibrary(module ModuleConfig, lib string) string {
path := module.LibraryPaths[lib]
if path == "" {
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index 46d8795..1467a02 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -22,6 +22,7 @@
"path/filepath"
"runtime"
+ "android/soong/android"
"android/soong/dexpreopt"
"github.com/google/blueprint/pathtools"
@@ -121,7 +122,7 @@
panic(err)
}
- write := func(rule *dexpreopt.Rule, file string) {
+ write := func(rule *android.RuleBuilder, file string) {
script := &bytes.Buffer{}
script.WriteString(scriptHeader)
for _, c := range rule.Commands() {
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 073d463..40c694f 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -15,6 +15,7 @@
package dexpreopt
import (
+ "android/soong/android"
"reflect"
"strings"
"testing"
@@ -35,6 +36,7 @@
DefaultCompilerFilter: "",
SystemServerCompilerFilter: "",
GenerateDMFiles: false,
+ NeverAllowStripping: false,
NoDebugInfo: false,
AlwaysSystemServerDebugInfo: false,
NeverSystemServerDebugInfo: false,
@@ -47,7 +49,7 @@
Dex2oatXmx: "",
Dex2oatXms: "",
EmptyDirectory: "",
- DefaultDexPreoptImageLocation: nil,
+ DefaultDexPreoptImage: nil,
CpuVariant: nil,
InstructionSetFeatures: nil,
Tools: Tools{
@@ -62,29 +64,28 @@
}
var testModuleConfig = ModuleConfig{
- Name: "",
- DexLocation: "",
- BuildPath: "",
- DexPath: "",
- UseEmbeddedDex: false,
- UncompressedDex: false,
- HasApkLibraries: false,
- PreoptFlags: nil,
- ProfileClassListing: "",
- ProfileIsTextListing: false,
- EnforceUsesLibraries: false,
- OptionalUsesLibraries: nil,
- UsesLibraries: nil,
- LibraryPaths: nil,
- Archs: nil,
- DexPreoptImageLocation: "",
- PreoptExtractedApk: false,
- NoCreateAppImage: false,
- ForceCreateAppImage: false,
- PresignedPrebuilt: false,
- NoStripping: false,
- StripInputPath: "",
- StripOutputPath: "",
+ Name: "",
+ DexLocation: "",
+ BuildPath: "",
+ DexPath: "",
+ UncompressedDex: false,
+ HasApkLibraries: false,
+ PreoptFlags: nil,
+ ProfileClassListing: "",
+ ProfileIsTextListing: false,
+ EnforceUsesLibraries: false,
+ OptionalUsesLibraries: nil,
+ UsesLibraries: nil,
+ LibraryPaths: nil,
+ Archs: []android.ArchType{android.Arm},
+ DexPreoptImages: []string{"system/framework/arm/boot.art"},
+ PreoptExtractedApk: false,
+ NoCreateAppImage: false,
+ ForceCreateAppImage: false,
+ PresignedPrebuilt: false,
+ NoStripping: false,
+ StripInputPath: "",
+ StripOutputPath: "",
}
func TestDexPreopt(t *testing.T) {
@@ -93,14 +94,13 @@
module.Name = "test"
module.DexLocation = "/system/app/test/test.apk"
module.BuildPath = "out/test/test.apk"
- module.Archs = []string{"arm"}
rule, err := GenerateDexpreoptRule(global, module)
if err != nil {
t.Error(err)
}
- wantInstalls := []Install{
+ wantInstalls := android.RuleBuilderInstalls{
{"out/test/oat/arm/package.odex", "/system/app/test/oat/arm/test.odex"},
{"out/test/oat/arm/package.vdex", "/system/app/test/oat/arm/test.vdex"},
}
@@ -110,6 +110,22 @@
}
}
+func TestDexPreoptStrip(t *testing.T) {
+ // Test that we panic if we strip in a configuration where stripping is not allowed.
+ global, module := testGlobalConfig, testModuleConfig
+
+ global.NeverAllowStripping = true
+ module.NoStripping = false
+ module.Name = "test"
+ module.DexLocation = "/system/app/test/test.apk"
+ module.BuildPath = "out/test/test.apk"
+
+ _, err := GenerateStripRule(global, module)
+ if err == nil {
+ t.Errorf("Expected an error when calling GenerateStripRule on a stripped module")
+ }
+}
+
func TestDexPreoptSystemOther(t *testing.T) {
global, module := testGlobalConfig, testModuleConfig
@@ -119,14 +135,13 @@
module.Name = "test"
module.DexLocation = "/system/app/test/test.apk"
module.BuildPath = "out/test/test.apk"
- module.Archs = []string{"arm"}
rule, err := GenerateDexpreoptRule(global, module)
if err != nil {
t.Error(err)
}
- wantInstalls := []Install{
+ wantInstalls := android.RuleBuilderInstalls{
{"out/test/oat/arm/package.odex", "/system_other/app/test/oat/arm/test.odex"},
{"out/test/oat/arm/package.vdex", "/system_other/app/test/oat/arm/test.vdex"},
}
@@ -143,14 +158,13 @@
module.DexLocation = "/system/app/test/test.apk"
module.BuildPath = "out/test/test.apk"
module.ProfileClassListing = "profile"
- module.Archs = []string{"arm"}
rule, err := GenerateDexpreoptRule(global, module)
if err != nil {
t.Error(err)
}
- wantInstalls := []Install{
+ wantInstalls := android.RuleBuilderInstalls{
{"out/test/profile.prof", "/system/app/test/test.apk.prof"},
{"out/test/oat/arm/package.art", "/system/app/test/oat/arm/test.art"},
{"out/test/oat/arm/package.odex", "/system/app/test/oat/arm/test.odex"},
@@ -193,7 +207,6 @@
module.Name = "test"
module.DexLocation = "/system/app/test/test.apk"
module.BuildPath = "out/test/test.apk"
- module.Archs = []string{"arm"}
module.StripInputPath = "$1"
module.StripOutputPath = "$2"
diff --git a/dexpreopt/script.go b/dexpreopt/script.go
deleted file mode 100644
index 9d4329c..0000000
--- a/dexpreopt/script.go
+++ /dev/null
@@ -1,178 +0,0 @@
-// 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.
-
-package dexpreopt
-
-import (
- "fmt"
- "sort"
- "strings"
-)
-
-type Install struct {
- From, To string
-}
-
-type Rule struct {
- commands []*Command
- installs []Install
-}
-
-func (r *Rule) Install(from, to string) {
- r.installs = append(r.installs, Install{from, to})
-}
-
-func (r *Rule) Command() *Command {
- command := &Command{}
- r.commands = append(r.commands, command)
- return command
-}
-
-func (r *Rule) Inputs() []string {
- outputs := r.outputSet()
-
- inputs := make(map[string]bool)
- for _, c := range r.commands {
- for _, input := range c.inputs {
- if !outputs[input] {
- inputs[input] = true
- }
- }
- }
-
- var inputList []string
- for input := range inputs {
- inputList = append(inputList, input)
- }
- sort.Strings(inputList)
-
- return inputList
-}
-
-func (r *Rule) outputSet() map[string]bool {
- outputs := make(map[string]bool)
- for _, c := range r.commands {
- for _, output := range c.outputs {
- outputs[output] = true
- }
- }
- return outputs
-}
-
-func (r *Rule) Outputs() []string {
- outputs := r.outputSet()
-
- var outputList []string
- for output := range outputs {
- outputList = append(outputList, output)
- }
- sort.Strings(outputList)
- return outputList
-}
-
-func (r *Rule) Installs() []Install {
- return append([]Install(nil), r.installs...)
-}
-
-func (r *Rule) Tools() []string {
- var tools []string
- for _, c := range r.commands {
- tools = append(tools, c.tools...)
- }
- return tools
-}
-
-func (r *Rule) Commands() []string {
- var commands []string
- for _, c := range r.commands {
- commands = append(commands, string(c.buf))
- }
- return commands
-}
-
-type Command struct {
- buf []byte
- inputs []string
- outputs []string
- tools []string
-}
-
-func (c *Command) Text(text string) *Command {
- if len(c.buf) > 0 {
- c.buf = append(c.buf, ' ')
- }
- c.buf = append(c.buf, text...)
- return c
-}
-
-func (c *Command) Textf(format string, a ...interface{}) *Command {
- return c.Text(fmt.Sprintf(format, a...))
-}
-
-func (c *Command) Flag(flag string) *Command {
- return c.Text(flag)
-}
-
-func (c *Command) FlagWithArg(flag, arg string) *Command {
- return c.Text(flag + arg)
-}
-
-func (c *Command) FlagWithList(flag string, list []string, sep string) *Command {
- return c.Text(flag + strings.Join(list, sep))
-}
-
-func (c *Command) Tool(path string) *Command {
- c.tools = append(c.tools, path)
- return c.Text(path)
-}
-
-func (c *Command) Input(path string) *Command {
- c.inputs = append(c.inputs, path)
- return c.Text(path)
-}
-
-func (c *Command) Implicit(path string) *Command {
- c.inputs = append(c.inputs, path)
- return c
-}
-
-func (c *Command) Implicits(paths []string) *Command {
- c.inputs = append(c.inputs, paths...)
- return c
-}
-
-func (c *Command) Output(path string) *Command {
- c.outputs = append(c.outputs, path)
- return c.Text(path)
-}
-
-func (c *Command) ImplicitOutput(path string) *Command {
- c.outputs = append(c.outputs, path)
- return c
-}
-
-func (c *Command) FlagWithInput(flag, path string) *Command {
- c.inputs = append(c.inputs, path)
- return c.Text(flag + path)
-}
-
-func (c *Command) FlagWithInputList(flag string, paths []string, sep string) *Command {
- c.inputs = append(c.inputs, paths...)
- return c.FlagWithList(flag, paths, sep)
-}
-
-func (c *Command) FlagWithOutput(flag, path string) *Command {
- c.outputs = append(c.outputs, path)
- return c.Text(flag + path)
-}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 77bc196..7695ffb 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -528,9 +528,6 @@
func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
-func (d *Defaults) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func defaultsFactory() android.Module {
return DefaultsFactory()
}
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 70b9090..19b22f7 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -519,8 +519,6 @@
return module
}
-func (t *testTool) DepsMutator(ctx android.BottomUpMutatorContext) {}
-
func (t *testTool) GenerateAndroidBuildActions(ctx android.ModuleContext) {
t.outputFile = android.PathForTesting("out", ctx.ModuleName())
}
diff --git a/java/aar.go b/java/aar.go
index d08e487..60fbe29 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -26,6 +26,7 @@
Dependency
ExportPackage() android.Path
ExportedProguardFlagFiles() android.Paths
+ ExportedRRODirs() android.Paths
ExportedStaticPackages() android.Paths
ExportedManifest() android.Path
}
@@ -52,11 +53,13 @@
Aapt_include_all_resources *bool
// list of directories relative to the Blueprints file containing assets.
- // Defaults to "assets"
+ // Defaults to ["assets"] if a directory called assets exists. Set to []
+ // to disable the default.
Asset_dirs []string
// list of directories relative to the Blueprints file containing
- // Android resources
+ // Android resources. Defaults to ["res"] if a directory called res exists.
+ // Set to [] to disable the default.
Resource_dirs []string
// path to AndroidManifest.xml. If unset, defaults to "AndroidManifest.xml".
@@ -72,6 +75,8 @@
rTxt android.Path
extraAaptPackagesFile android.Path
isLibrary bool
+ uncompressedJNI bool
+ useEmbeddedDex bool
aaptProperties aaptProperties
}
@@ -80,6 +85,14 @@
return a.exportPackage
}
+func (a *aapt) ExportedRRODirs() android.Paths {
+ return a.rroDirs
+}
+
+func (a *aapt) ExportedManifest() android.Path {
+ return a.manifestPath
+}
+
func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext, manifestPath android.Path) (flags []string,
deps android.Paths, resDirs, overlayDirs []globbedResourceDir, rroDirs android.Paths) {
@@ -164,16 +177,21 @@
}
func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, extraLinkFlags ...string) {
- transitiveStaticLibs, staticLibManifests, libDeps, libFlags := aaptLibs(ctx, sdkContext)
+ transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext)
// App manifest file
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
- manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary)
+ manifestPath := manifestMerger(ctx, manifestSrcPath, sdkContext, staticLibManifests, a.isLibrary,
+ a.uncompressedJNI, a.useEmbeddedDex)
linkFlags, linkDeps, resDirs, overlayDirs, rroDirs := a.aapt2Flags(ctx, sdkContext, manifestPath)
+ rroDirs = append(rroDirs, staticRRODirs...)
+ // TODO(b/124035856): stop de-duping when there are no more dupe resource dirs.
+ rroDirs = android.FirstUniquePaths(rroDirs)
+
linkFlags = append(linkFlags, libFlags...)
linkDeps = append(linkDeps, libDeps...)
linkFlags = append(linkFlags, extraLinkFlags...)
@@ -235,7 +253,7 @@
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, staticLibManifests,
- deps android.Paths, flags []string) {
+ staticRRODirs, deps android.Paths, flags []string) {
var sharedLibs android.Paths
@@ -263,6 +281,7 @@
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
staticLibManifests = append(staticLibManifests, aarDep.ExportedManifest())
+ staticRRODirs = append(staticRRODirs, aarDep.ExportedRRODirs()...)
}
}
})
@@ -279,8 +298,9 @@
}
transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
+ staticRRODirs = android.FirstUniquePaths(staticRRODirs)
- return transitiveStaticLibs, staticLibManifests, deps, flags
+ return transitiveStaticLibs, staticLibManifests, staticRRODirs, deps, flags
}
type AndroidLibrary struct {
@@ -303,10 +323,6 @@
return a.exportedStaticPackages
}
-func (a *AndroidLibrary) ExportedManifest() android.Path {
- return a.manifestPath
-}
-
var _ AndroidLibraryDependency = (*AndroidLibrary)(nil)
func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -317,7 +333,7 @@
}
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- a.isLibrary = true
+ a.aapt.isLibrary = true
a.aapt.buildActions(ctx, sdkContext(a))
ctx.CheckbuildFile(a.proguardOptionsFile)
@@ -351,6 +367,12 @@
a.exportedStaticPackages = android.FirstUniquePaths(a.exportedStaticPackages)
}
+// android_library builds and links sources into a `.jar` file for the device along with Android resources.
+//
+// An android_library has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the device bootclasspath, along with a `package-res.apk` file containing Android resources compiled
+// with aapt2. This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of
+// an android_app module.
func AndroidLibraryFactory() android.Module {
module := &AndroidLibrary{}
@@ -426,6 +448,10 @@
return android.Paths{a.proguardFlags}
}
+func (a *AARImport) ExportedRRODirs() android.Paths {
+ return nil
+}
+
func (a *AARImport) ExportedStaticPackages() android.Paths {
return a.exportedStaticPackages
}
@@ -518,9 +544,10 @@
linkFlags = append(linkFlags, "--manifest "+a.manifest.String())
linkDeps = append(linkDeps, a.manifest)
- transitiveStaticLibs, staticLibManifests, libDeps, libFlags := aaptLibs(ctx, sdkContext(a))
+ transitiveStaticLibs, staticLibManifests, staticRRODirs, libDeps, libFlags := aaptLibs(ctx, sdkContext(a))
_ = staticLibManifests
+ _ = staticRRODirs
linkDeps = append(linkDeps, libDeps...)
linkFlags = append(linkFlags, libFlags...)
@@ -549,6 +576,10 @@
return android.Paths{a.classpathFile}
}
+func (a *AARImport) DexJar() android.Path {
+ return nil
+}
+
func (a *AARImport) AidlIncludeDirs() android.Paths {
return nil
}
@@ -559,6 +590,10 @@
var _ android.PrebuiltInterface = (*Import)(nil)
+// android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
+//
+// This module is not suitable for installing on a device, but can be used as a `static_libs` dependency of
+// an android_app module.
func AARImportFactory() android.Module {
module := &AARImport{}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 36f24ff..e63fb80 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -15,12 +15,13 @@
package java
import (
- "android/soong/java/config"
+ "fmt"
"strings"
"github.com/google/blueprint"
"android/soong/android"
+ "android/soong/java/config"
)
var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
@@ -43,11 +44,26 @@
"libs")
func manifestMerger(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext,
- staticLibManifests android.Paths, isLibrary bool) android.Path {
+ staticLibManifests android.Paths, isLibrary bool, uncompressedJNI, useEmbeddedDex bool) android.Path {
var args []string
if isLibrary {
args = append(args, "--library")
+ } else {
+ minSdkVersion, err := sdkVersionToNumber(ctx, sdkContext.minSdkVersion())
+ if err != nil {
+ ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+ }
+ if minSdkVersion >= 23 {
+ args = append(args, fmt.Sprintf("--extract-native-libs=%v", !uncompressedJNI))
+ } else if uncompressedJNI {
+ ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
+ minSdkVersion)
+ }
+ }
+
+ if useEmbeddedDex {
+ args = append(args, "--use-embedded-dex=true")
}
// Inject minSdkVersion into the manifest
diff --git a/java/android_resources.go b/java/android_resources.go
index efd3e3d..44cb709 100644
--- a/java/android_resources.go
+++ b/java/android_resources.go
@@ -46,7 +46,7 @@
paths android.DirectorySortedPaths
}
-const overlayDataKey = "overlayDataKey"
+var overlayDataKey = android.NewOnceKey("overlayDataKey")
type globbedResourceDir struct {
dir android.Path
diff --git a/java/androidmk.go b/java/androidmk.go
index 089ed4f..04b328d 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -65,7 +65,7 @@
fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
}
if len(library.dexpreopter.builtInstalled) > 0 {
- fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", strings.Join(library.dexpreopter.builtInstalled, " "))
+ fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", library.dexpreopter.builtInstalled)
}
fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", library.sdkVersion())
fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", library.implementationAndResourcesJar.String())
@@ -166,7 +166,7 @@
fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", binary.dexJarFile.String())
}
if len(binary.dexpreopter.builtInstalled) > 0 {
- fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", strings.Join(binary.dexpreopter.builtInstalled, " "))
+ fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", binary.dexpreopter.builtInstalled)
}
},
},
@@ -203,6 +203,11 @@
Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
Extra: []android.AndroidMkExtraFunc{
func(w io.Writer, outputFile android.Path) {
+ // TODO(jungjw): This, outputting two LOCAL_MODULE lines, works, but is not ideal. Find a better solution.
+ if app.Name() != app.installApkName {
+ fmt.Fprintln(w, "# Overridden by PRODUCT_PACKAGE_NAME_OVERRIDES")
+ fmt.Fprintln(w, "LOCAL_MODULE :=", app.installApkName)
+ }
fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", app.exportPackage.String())
if app.dexJarFile != nil {
fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String())
@@ -247,21 +252,32 @@
}
fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", app.certificate.Pem.String())
- if len(app.appProperties.Overrides) > 0 {
- fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES := "+strings.Join(app.appProperties.Overrides, " "))
+ if overriddenPkgs := app.getOverriddenPackages(); len(overriddenPkgs) > 0 {
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_PACKAGES :=", strings.Join(overriddenPkgs, " "))
}
for _, jniLib := range app.installJniLibs {
fmt.Fprintln(w, "LOCAL_SOONG_JNI_LIBS_"+jniLib.target.Arch.ArchType.String(), "+=", jniLib.name)
}
if len(app.dexpreopter.builtInstalled) > 0 {
- fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", strings.Join(app.dexpreopter.builtInstalled, " "))
+ fmt.Fprintln(w, "LOCAL_SOONG_BUILT_INSTALLED :=", app.dexpreopter.builtInstalled)
}
},
},
}
}
+func (a *AndroidApp) getOverriddenPackages() []string {
+ var overridden []string
+ if len(a.appProperties.Overrides) > 0 {
+ overridden = append(overridden, a.appProperties.Overrides...)
+ }
+ if a.Name() != a.installApkName {
+ overridden = append(overridden, a.Name())
+ }
+ return overridden
+}
+
func (a *AndroidTest) AndroidMk() android.AndroidMkData {
data := a.AndroidApp.AndroidMk()
data.Extra = append(data.Extra, func(w io.Writer, outputFile android.Path) {
diff --git a/java/app.go b/java/app.go
index cc863e6..3cb7e8e 100644
--- a/java/app.go
+++ b/java/app.go
@@ -68,7 +68,15 @@
// list of native libraries that will be provided in or alongside the resulting jar
Jni_libs []string `android:"arch_variant"`
- EmbedJNI bool `blueprint:"mutated"`
+ // Store native libraries uncompressed in the APK and set the android:extractNativeLibs="false" manifest
+ // flag so that they are used from inside the APK at runtime. Defaults to true for android_test modules unless
+ // sdk_version or min_sdk_version is set to a version that doesn't support it (<23), defaults to false for other
+ // module types where the native libraries are generally preinstalled outside the APK.
+ Use_embedded_native_libs *bool
+
+ // Store dex files uncompressed in the APK and set the android:useEmbeddedDex="true" manifest attribute so that
+ // they are used from inside the APK at runtime.
+ Use_embedded_dex *bool
}
type AndroidApp struct {
@@ -95,10 +103,6 @@
return nil
}
-func (a *AndroidApp) ExportedManifest() android.Path {
- return a.manifestPath
-}
-
var _ AndroidLibraryDependency = (*AndroidApp)(nil)
type Certificate struct {
@@ -140,19 +144,45 @@
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ a.aapt.uncompressedJNI = a.shouldUncompressJNI(ctx)
+ a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex)
a.generateAndroidBuildActions(ctx)
}
+// shouldUncompressJNI returns true if the native libraries should be stored in the APK uncompressed and the
+// extractNativeLibs application flag should be set to false in the manifest.
+func (a *AndroidApp) shouldUncompressJNI(ctx android.ModuleContext) bool {
+ minSdkVersion, err := sdkVersionToNumber(ctx, a.minSdkVersion())
+ if err != nil {
+ ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.minSdkVersion(), err)
+ }
+
+ return minSdkVersion >= 23 && Bool(a.appProperties.Use_embedded_native_libs)
+}
+
// Returns whether this module should have the dex file stored uncompressed in the APK.
func (a *AndroidApp) shouldUncompressDex(ctx android.ModuleContext) bool {
+ if Bool(a.appProperties.Use_embedded_dex) {
+ return true
+ }
+
if ctx.Config().UnbundledBuild() {
return false
}
// Uncompress dex in APKs of privileged apps, and modules used by privileged apps.
- return ctx.Config().UncompressPrivAppDex() &&
+ if ctx.Config().UncompressPrivAppDex() &&
(Bool(a.appProperties.Privileged) ||
- inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules()))
+ inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules())) {
+ return true
+ }
+
+ // Uncompress if the dex files is preopted on /system.
+ if !a.dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, a.dexpreopter.installPath)) {
+ return true
+ }
+
+ return false
}
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
@@ -211,7 +241,6 @@
}
func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
- a.deviceProperties.UncompressDex = a.shouldUncompressDex(ctx)
var installDir string
if ctx.ModuleName() == "framework-res" {
@@ -223,6 +252,9 @@
installDir = filepath.Join("app", a.installApkName)
}
a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
+ a.dexpreopter.isInstallable = Bool(a.properties.Installable)
+ a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx)
+ a.deviceProperties.UncompressDex = a.dexpreopter.uncompressedDex
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
@@ -234,10 +266,10 @@
func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, ctx android.ModuleContext) android.WritablePath {
var jniJarFile android.WritablePath
if len(jniLibs) > 0 {
- embedJni := ctx.Config().UnbundledBuild() || a.appProperties.EmbedJNI
+ embedJni := ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs)
if embedJni {
jniJarFile = android.PathForModuleOut(ctx, "jnilibs.zip")
- TransformJniLibsToJar(ctx, jniJarFile, jniLibs)
+ TransformJniLibsToJar(ctx, jniJarFile, jniLibs, a.shouldUncompressJNI(ctx))
} else {
a.installJniLibs = jniLibs
}
@@ -363,6 +395,7 @@
return String(a.appProperties.Certificate)
}
+// android_app compiles sources and Android resources into an Android application package `.apk` file.
func AndroidAppFactory() android.Module {
module := &AndroidApp{}
@@ -425,6 +458,8 @@
}
}
+// android_test compiles test sources and Android resources into an Android application package `.apk` file and
+// creates an `AndroidTest.xml` file to allow running the test with `atest` or a `TEST_MAPPING` file.
func AndroidTestFactory() android.Module {
module := &AndroidTest{}
@@ -432,7 +467,7 @@
module.Module.properties.Instrument = true
module.Module.properties.Installable = proptools.BoolPtr(true)
- module.appProperties.EmbedJNI = true
+ module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
module.AddProperties(
@@ -462,13 +497,16 @@
appTestHelperAppProperties appTestHelperAppProperties
}
+// android_test_helper_app compiles sources and Android resources into an Android application package `.apk` file that
+// will be used by tests, but does not produce an `AndroidTest.xml` file so the module will not be run directly as a
+// test.
func AndroidTestHelperAppFactory() android.Module {
module := &AndroidTestHelperApp{}
module.Module.deviceProperties.Optimize.Enabled = proptools.BoolPtr(true)
module.Module.properties.Installable = proptools.BoolPtr(true)
- module.appProperties.EmbedJNI = true
+ module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
module.Module.dexpreopter.isTest = true
module.AddProperties(
@@ -496,6 +534,8 @@
Certificate *string
}
+// android_app_certificate modules can be referenced by the certificates property of android_app modules to select
+// the signing key.
func AndroidAppCertificateFactory() android.Module {
module := &AndroidAppCertificate{}
module.AddProperties(&module.properties)
@@ -503,9 +543,6 @@
return module
}
-func (c *AndroidAppCertificate) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func (c *AndroidAppCertificate) GenerateAndroidBuildActions(ctx android.ModuleContext) {
cert := String(c.properties.Certificate)
c.Certificate = Certificate{
diff --git a/java/app_builder.go b/java/app_builder.go
index 5b999d8..6cc2159 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -200,14 +200,14 @@
}
func TransformJniLibsToJar(ctx android.ModuleContext, outputFile android.WritablePath,
- jniLibs []jniLib) {
+ jniLibs []jniLib, uncompressJNI bool) {
var deps android.Paths
jarArgs := []string{
"-j", // junk paths, they will be added back with -P arguments
}
- if !ctx.Config().UnbundledBuild() {
+ if uncompressJNI {
jarArgs = append(jarArgs, "-L 0")
}
diff --git a/java/app_test.go b/java/app_test.go
index 21bda3c..103f24b 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -106,68 +106,144 @@
}
}
-var testEnforceRROTests = []struct {
- name string
- enforceRROTargets []string
- enforceRROExcludedOverlays []string
- overlayFiles map[string][]string
- rroDirs map[string][]string
-}{
- {
- name: "no RRO",
- enforceRROTargets: nil,
- enforceRROExcludedOverlays: nil,
- overlayFiles: map[string][]string{
- "foo": []string{
- "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
- "device/vendor/blah/overlay/foo/res/values/strings.xml",
- },
- "bar": []string{
- "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
- "device/vendor/blah/overlay/bar/res/values/strings.xml",
- },
+func TestResourceDirs(t *testing.T) {
+ testCases := []struct {
+ name string
+ prop string
+ resources []string
+ }{
+ {
+ name: "no resource_dirs",
+ prop: "",
+ resources: []string{"res/res/values/strings.xml"},
},
- rroDirs: map[string][]string{
- "foo": nil,
- "bar": nil,
+ {
+ name: "resource_dirs",
+ prop: `resource_dirs: ["res"]`,
+ resources: []string{"res/res/values/strings.xml"},
},
- },
- {
- name: "enforce RRO on foo",
- enforceRROTargets: []string{"foo"},
- enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
- overlayFiles: map[string][]string{
- "foo": []string{"device/vendor/blah/static_overlay/foo/res/values/strings.xml"},
- "bar": []string{
- "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
- "device/vendor/blah/overlay/bar/res/values/strings.xml",
- },
+ {
+ name: "empty resource_dirs",
+ prop: `resource_dirs: []`,
+ resources: nil,
},
- rroDirs: map[string][]string{
- "foo": []string{"device/vendor/blah/overlay/foo/res"},
- "bar": nil,
- },
- },
- {
- name: "enforce RRO on all",
- enforceRROTargets: []string{"*"},
- enforceRROExcludedOverlays: []string{
- // Excluding specific apps/res directories also allowed.
- "device/vendor/blah/static_overlay/foo",
- "device/vendor/blah/static_overlay/bar/res",
- },
- overlayFiles: map[string][]string{
- "foo": []string{"device/vendor/blah/static_overlay/foo/res/values/strings.xml"},
- "bar": []string{"device/vendor/blah/static_overlay/bar/res/values/strings.xml"},
- },
- rroDirs: map[string][]string{
- "foo": []string{"device/vendor/blah/overlay/foo/res"},
- "bar": []string{"device/vendor/blah/overlay/bar/res"},
- },
- },
+ }
+
+ fs := map[string][]byte{
+ "res/res/values/strings.xml": nil,
+ }
+
+ bp := `
+ android_app {
+ name: "foo",
+ %s
+ }
+ `
+
+ for _, testCase := range testCases {
+ t.Run(testCase.name, func(t *testing.T) {
+ config := testConfig(nil)
+ ctx := testContext(config, fmt.Sprintf(bp, testCase.prop), fs)
+ run(t, ctx, config)
+
+ module := ctx.ModuleForTests("foo", "android_common")
+ resourceList := module.MaybeOutput("aapt2/res.list")
+
+ var resources []string
+ if resourceList.Rule != nil {
+ for _, compiledResource := range resourceList.Inputs.Strings() {
+ resources = append(resources, module.Output(compiledResource).Inputs.Strings()...)
+ }
+ }
+
+ if !reflect.DeepEqual(resources, testCase.resources) {
+ t.Errorf("expected resource files %q, got %q",
+ testCase.resources, resources)
+ }
+ })
+ }
}
func TestEnforceRRO(t *testing.T) {
+ testCases := []struct {
+ name string
+ enforceRROTargets []string
+ enforceRROExcludedOverlays []string
+ overlayFiles map[string][]string
+ rroDirs map[string][]string
+ }{
+ {
+ name: "no RRO",
+ enforceRROTargets: nil,
+ enforceRROExcludedOverlays: nil,
+ overlayFiles: map[string][]string{
+ "foo": []string{
+ buildDir + "/.intermediates/lib/android_common/package-res.apk",
+ "foo/res/res/values/strings.xml",
+ "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+ "device/vendor/blah/overlay/foo/res/values/strings.xml",
+ },
+ "bar": []string{
+ "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+ "device/vendor/blah/overlay/bar/res/values/strings.xml",
+ },
+ },
+ rroDirs: map[string][]string{
+ "foo": nil,
+ "bar": nil,
+ },
+ },
+ {
+ name: "enforce RRO on foo",
+ enforceRROTargets: []string{"foo"},
+ enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
+ overlayFiles: map[string][]string{
+ "foo": []string{
+ buildDir + "/.intermediates/lib/android_common/package-res.apk",
+ "foo/res/res/values/strings.xml",
+ "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+ },
+ "bar": []string{
+ "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+ "device/vendor/blah/overlay/bar/res/values/strings.xml",
+ },
+ },
+
+ rroDirs: map[string][]string{
+ "foo": []string{
+ "device/vendor/blah/overlay/foo/res",
+ // Enforce RRO on "foo" could imply RRO on static dependencies, but for now it doesn't.
+ // "device/vendor/blah/overlay/lib/res",
+ },
+ "bar": nil,
+ },
+ },
+ {
+ name: "enforce RRO on all",
+ enforceRROTargets: []string{"*"},
+ enforceRROExcludedOverlays: []string{
+ // Excluding specific apps/res directories also allowed.
+ "device/vendor/blah/static_overlay/foo",
+ "device/vendor/blah/static_overlay/bar/res",
+ },
+ overlayFiles: map[string][]string{
+ "foo": []string{
+ buildDir + "/.intermediates/lib/android_common/package-res.apk",
+ "foo/res/res/values/strings.xml",
+ "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+ },
+ "bar": []string{"device/vendor/blah/static_overlay/bar/res/values/strings.xml"},
+ },
+ rroDirs: map[string][]string{
+ "foo": []string{
+ "device/vendor/blah/overlay/foo/res",
+ "device/vendor/blah/overlay/lib/res",
+ },
+ "bar": []string{"device/vendor/blah/overlay/bar/res"},
+ },
+ },
+ }
+
resourceOverlays := []string{
"device/vendor/blah/overlay",
"device/vendor/blah/overlay2",
@@ -177,8 +253,10 @@
fs := map[string][]byte{
"foo/res/res/values/strings.xml": nil,
"bar/res/res/values/strings.xml": nil,
+ "lib/res/res/values/strings.xml": nil,
"device/vendor/blah/overlay/foo/res/values/strings.xml": nil,
"device/vendor/blah/overlay/bar/res/values/strings.xml": nil,
+ "device/vendor/blah/overlay/lib/res/values/strings.xml": nil,
"device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil,
"device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil,
"device/vendor/blah/overlay2/res/values/strings.xml": nil,
@@ -188,23 +266,29 @@
android_app {
name: "foo",
resource_dirs: ["foo/res"],
+ static_libs: ["lib"],
}
android_app {
name: "bar",
resource_dirs: ["bar/res"],
}
+
+ android_library {
+ name: "lib",
+ resource_dirs: ["lib/res"],
+ }
`
- for _, testCase := range testEnforceRROTests {
+ for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
config := testConfig(nil)
- config.TestProductVariables.ResourceOverlays = &resourceOverlays
+ config.TestProductVariables.ResourceOverlays = resourceOverlays
if testCase.enforceRROTargets != nil {
- config.TestProductVariables.EnforceRROTargets = &testCase.enforceRROTargets
+ config.TestProductVariables.EnforceRROTargets = testCase.enforceRROTargets
}
if testCase.enforceRROExcludedOverlays != nil {
- config.TestProductVariables.EnforceRROExcludedOverlays = &testCase.enforceRROExcludedOverlays
+ config.TestProductVariables.EnforceRROExcludedOverlays = testCase.enforceRROExcludedOverlays
}
ctx := testAppContext(config, bp, fs)
@@ -216,7 +300,15 @@
var overlayFiles []string
if overlayFile.Rule != nil {
for _, o := range overlayFile.Inputs.Strings() {
- overlayFiles = append(overlayFiles, module.Output(o).Inputs.Strings()...)
+ overlayOutput := module.MaybeOutput(o)
+ if overlayOutput.Rule != nil {
+ // If the overlay is compiled as part of this module (i.e. a .arsc.flat file),
+ // verify the inputs to the .arsc.flat rule.
+ overlayFiles = append(overlayFiles, overlayOutput.Inputs.Strings()...)
+ } else {
+ // Otherwise, verify the full path to the output of the other module
+ overlayFiles = append(overlayFiles, o)
+ }
}
}
diff --git a/java/builder.go b/java/builder.go
index 7aac881..aa61a85 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -122,8 +122,8 @@
zipalign = pctx.AndroidStaticRule("zipalign",
blueprint.RuleParams{
- Command: "if ! ${config.ZipAlign} -c 4 $in > /dev/null; then " +
- "${config.ZipAlign} -f 4 $in $out; " +
+ Command: "if ! ${config.ZipAlign} -c -p 4 $in > /dev/null; then " +
+ "${config.ZipAlign} -f -p 4 $in $out; " +
"else " +
"cp -f $in $out; " +
"fi",
diff --git a/java/config/config.go b/java/config/config.go
index 5c838a5..75be9e2 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -33,6 +33,12 @@
DefaultLambdaStubsLibrary = "core-lambda-stubs"
SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar"
+ // A list of the jars that provide information about usages of the hidden API.
+ HiddenAPIExtraAppUsageJars = []string{
+ // The core-oj-hiddenapi provides information for the core-oj jar.
+ "core-oj-hiddenapi",
+ }
+
DefaultJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"}
InstrumentFrameworkModules = []string{
@@ -107,6 +113,7 @@
pctx.HostBinToolVariable("ApiCheckCmd", "apicheck")
pctx.HostBinToolVariable("D8Cmd", "d8")
pctx.HostBinToolVariable("R8Cmd", "r8-compat-proguard")
+ pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi")
pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string {
turbine := "turbine.jar"
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 6e46bc9..127deab 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -15,12 +15,6 @@
package java
import (
- "path/filepath"
- "strings"
-
- "github.com/google/blueprint"
- "github.com/google/blueprint/proptools"
-
"android/soong/android"
"android/soong/dexpreopt"
)
@@ -34,7 +28,7 @@
isTest bool
isInstallable bool
- builtInstalled []string
+ builtInstalled string
}
type DexpreoptProperties struct {
@@ -87,12 +81,10 @@
return false
}
-func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath {
- if d.dexpreoptDisabled(ctx) {
- return dexJarFile
- }
+var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
- globalConfig := ctx.Config().Once("DexpreoptGlobalConfig", func() interface{} {
+func getGlobalConfig(ctx android.ModuleContext) dexpreopt.GlobalConfig {
+ globalConfig := ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
if f := ctx.Config().DexpreoptGlobalConfig(); f != "" {
ctx.AddNinjaFileDeps(f)
globalConfig, err := dexpreopt.LoadGlobalConfig(f)
@@ -103,15 +95,28 @@
}
return dexpreopt.GlobalConfig{}
}).(dexpreopt.GlobalConfig)
+ return globalConfig
+}
- var archs []string
+func odexOnSystemOther(ctx android.ModuleContext, installPath android.OutputPath) bool {
+ return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), getGlobalConfig(ctx))
+}
+
+func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath {
+ if d.dexpreoptDisabled(ctx) {
+ return dexJarFile
+ }
+
+ globalConfig := getGlobalConfig(ctx)
+
+ var archs []android.ArchType
for _, a := range ctx.MultiTargets() {
- archs = append(archs, a.Arch.ArchType.String())
+ archs = append(archs, a.Arch.ArchType)
}
if len(archs) == 0 {
// assume this is a java library, dexpreopt for all arches for now
for _, target := range ctx.Config().Targets[android.Android] {
- archs = append(archs, target.Arch.ArchType.String())
+ archs = append(archs, target.Arch.ArchType)
}
if inList(ctx.ModuleName(), globalConfig.SystemServerJars) && !d.isSDKLibrary {
// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
@@ -123,6 +128,11 @@
archs = archs[:1]
}
+ var images []string
+ for _, arch := range archs {
+ images = append(images, globalConfig.DefaultDexPreoptImage[arch])
+ }
+
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
strippedDexJarFile := android.PathForModuleOut(ctx, "dexpreopt", dexJarFile.Base())
@@ -153,7 +163,6 @@
DexLocation: dexLocation,
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").String(),
DexPath: dexJarFile.String(),
- UseEmbeddedDex: false,
UncompressedDex: d.uncompressedDex,
HasApkLibraries: false,
PreoptFlags: nil,
@@ -166,8 +175,8 @@
UsesLibraries: nil,
LibraryPaths: nil,
- Archs: archs,
- DexPreoptImageLocation: "",
+ Archs: archs,
+ DexPreoptImages: images,
PreoptExtractedApk: false,
@@ -185,42 +194,9 @@
return dexJarFile
}
- var inputs android.Paths
- for _, input := range dexpreoptRule.Inputs() {
- if input == "" {
- // Tests sometimes have empty configuration values that lead to empty inputs
- continue
- }
- rel, isRel := android.MaybeRel(ctx, android.PathForModuleOut(ctx).String(), input)
- if isRel {
- inputs = append(inputs, android.PathForModuleOut(ctx, rel))
- } else {
- // TODO: use PathForOutput once boot image is moved to where PathForOutput can find it.
- inputs = append(inputs, &bootImagePath{input})
- }
- }
+ dexpreoptRule.Build(pctx, ctx, "dexpreopt", "dexpreopt")
- var outputs android.WritablePaths
- for _, output := range dexpreoptRule.Outputs() {
- rel := android.Rel(ctx, android.PathForModuleOut(ctx).String(), output)
- outputs = append(outputs, android.PathForModuleOut(ctx, rel))
- }
-
- for _, install := range dexpreoptRule.Installs() {
- d.builtInstalled = append(d.builtInstalled, install.From+":"+install.To)
- }
-
- if len(dexpreoptRule.Commands()) > 0 {
- ctx.Build(pctx, android.BuildParams{
- Rule: ctx.Rule(pctx, "dexpreopt", blueprint.RuleParams{
- Command: strings.Join(proptools.NinjaEscape(dexpreoptRule.Commands()), " && "),
- CommandDeps: dexpreoptRule.Tools(),
- }),
- Implicits: inputs,
- Outputs: outputs,
- Description: "dexpreopt",
- })
- }
+ d.builtInstalled = dexpreoptRule.Installs().String()
stripRule, err := dexpreopt.GenerateStripRule(globalConfig, dexpreoptConfig)
if err != nil {
@@ -228,26 +204,7 @@
return dexJarFile
}
- ctx.Build(pctx, android.BuildParams{
- Rule: ctx.Rule(pctx, "dexpreopt_strip", blueprint.RuleParams{
- Command: strings.Join(proptools.NinjaEscape(stripRule.Commands()), " && "),
- CommandDeps: stripRule.Tools(),
- }),
- Input: dexJarFile,
- Output: strippedDexJarFile,
- Description: "dexpreopt strip",
- })
+ stripRule.Build(pctx, ctx, "dexpreopt_strip", "dexpreopt strip")
return strippedDexJarFile
}
-
-type bootImagePath struct {
- path string
-}
-
-var _ android.Path = (*bootImagePath)(nil)
-
-func (p *bootImagePath) String() string { return p.path }
-func (p *bootImagePath) Ext() string { return filepath.Ext(p.path) }
-func (p *bootImagePath) Base() string { return filepath.Base(p.path) }
-func (p *bootImagePath) Rel() string { return p.path }
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 01e2989..85e4797 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -171,12 +171,11 @@
// list of java libraries that will be in the classpath.
Libs []string `android:"arch_variant"`
- // don't build against the default libraries (bootclasspath, legacy-test, core-junit,
- // ext, and framework for device targets)
+ // don't build against the default libraries (bootclasspath, ext, and framework for device
+ // targets)
No_standard_libs *bool
- // don't build against the framework libraries (legacy-test, core-junit,
- // ext, and framework for device targets)
+ // don't build against the framework libraries (ext, and framework for device targets)
No_framework_libs *bool
// the java library (in classpath) for documentation that provides java srcs and srcjars.
@@ -599,6 +598,9 @@
case ".aidl":
javaFile := genAidl(ctx, srcFile, flags.aidlFlags)
outSrcFiles = append(outSrcFiles, javaFile)
+ case ".sysprop":
+ javaFile := genSysprop(ctx, srcFile)
+ outSrcFiles = append(outSrcFiles, javaFile)
default:
outSrcFiles = append(outSrcFiles, srcFile)
}
@@ -630,10 +632,10 @@
}
case libTag:
switch dep := module.(type) {
+ case SdkLibraryDependency:
+ deps.classpath = append(deps.classpath, dep.SdkImplementationJars(ctx, j.sdkVersion())...)
case Dependency:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
- case SdkLibraryDependency:
- deps.classpath = append(deps.classpath, dep.ImplementationJars(ctx, j.sdkVersion())...)
case android.SourceFileProducer:
checkProducesJars(ctx, dep)
deps.classpath = append(deps.classpath, dep.Srcs()...)
@@ -695,14 +697,17 @@
j.sourcepaths = android.PathsForModuleSrc(ctx, j.properties.Local_sourcepaths)
j.argFiles = ctx.ExpandSources(j.properties.Arg_files, nil)
- argFilesMap := map[string]android.Path{}
+ argFilesMap := map[string]string{}
+ argFileLabels := []string{}
- for _, f := range j.argFiles {
- if _, exists := argFilesMap[f.Rel()]; !exists {
- argFilesMap[f.Rel()] = f
+ for _, label := range j.properties.Arg_files {
+ var paths = ctx.ExpandSources([]string{label}, nil)
+ if _, exists := argFilesMap[label]; !exists {
+ argFilesMap[label] = strings.Join(paths.Strings(), " ")
+ argFileLabels = append(argFileLabels, label)
} else {
ctx.ModuleErrorf("multiple arg_files for %q, %q and %q",
- f, argFilesMap[f.Rel()], f.Rel())
+ label, argFilesMap[label], paths)
}
}
@@ -710,10 +715,11 @@
j.args, err = android.Expand(String(j.properties.Args), func(name string) (string, error) {
if strings.HasPrefix(name, "location ") {
label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
- if f, ok := argFilesMap[label]; ok {
- return f.String(), nil
+ if paths, ok := argFilesMap[label]; ok {
+ return paths, nil
} else {
- return "", fmt.Errorf("unknown location label %q", label)
+ return "", fmt.Errorf("unknown location label %q, expecting one of %q",
+ label, strings.Join(argFileLabels, ", "))
}
} else if name == "genDir" {
return android.PathForModuleGen(ctx).String(), nil
@@ -1816,9 +1822,6 @@
func (*DocDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
-func (d *DocDefaults) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func DocDefaultsFactory() android.Module {
module := &DocDefaults{}
diff --git a/java/genrule.go b/java/genrule.go
index 8f29482..25494ec 100644
--- a/java/genrule.go
+++ b/java/genrule.go
@@ -25,8 +25,37 @@
}
// java_genrule is a genrule that can depend on other java_* objects.
-// The cmd may be run multiple times, once for each of the different host/device
-// variations.
+//
+// By default a java_genrule has a single variant that will run against the device variant of its dependencies and
+// produce an output that can be used as an input to a device java rule.
+//
+// Specifying `host_supported: true` will produce two variants, one that uses device dependencie sand one that uses
+// host dependencies. Each variant will run the command.
+//
+// Use a java_genrule instead of a genrule when it needs to depend on or be depended on by other java modules, unless
+// the dependency is for a generated source file.
+//
+// Examples:
+//
+// Use a java_genrule to package generated java resources:
+//
+// java_genrule {
+// name: "generated_resources",
+// tools: [
+// "generator",
+// "soong_zip",
+// ],
+// srcs: ["generator_inputs/**/*"],
+// out: ["generated_android_icu4j_resources.jar"],
+// cmd: "$(location generator) $(in) -o $(genDir) " +
+// "&& $(location soong_zip) -o $(out) -C $(genDir)/res -D $(genDir)/res",
+// }
+//
+// java_library {
+// name: "lib_with_generated_resources",
+// srcs: ["src/**/*.java"],
+// static_libs: ["generated_resources"],
+// }
func genRuleFactory() android.Module {
module := genrule.NewGenRule()
@@ -36,8 +65,9 @@
}
// java_genrule_host is a genrule that can depend on other java_* objects.
-// The cmd may be run multiple times, once for each of the different host/device
-// variations.
+//
+// A java_genrule_host has a single variant that will run against the host variant of its dependencies and
+// produce an output that can be used as an input to a host java rule.
func genRuleFactoryHost() android.Module {
module := genrule.NewGenRule()
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 67df575..f199051 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -15,13 +15,12 @@
package java
import (
- "sort"
- "strings"
- "sync"
+ "path/filepath"
"github.com/google/blueprint"
"android/soong/android"
+ "android/soong/java/config"
)
var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", blueprint.RuleParams{
@@ -29,10 +28,60 @@
CommandDeps: []string{"${config.Class2Greylist}"},
}, "outFlag", "stubAPIFlags")
-func hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar android.Path) {
- flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
- metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv")
- stubFlagsCSV := &bootImagePath{ctx.Config().HiddenAPIStubFlags()}
+type hiddenAPI struct {
+ flagsCSVPath android.Path
+ metadataCSVPath android.Path
+ bootDexJarPath android.Path
+}
+
+func (h *hiddenAPI) flagsCSV() android.Path {
+ return h.flagsCSVPath
+}
+
+func (h *hiddenAPI) metadataCSV() android.Path {
+ return h.metadataCSVPath
+}
+
+func (h *hiddenAPI) bootDexJar() android.Path {
+ return h.bootDexJarPath
+}
+
+type hiddenAPIIntf interface {
+ flagsCSV() android.Path
+ metadataCSV() android.Path
+ bootDexJar() android.Path
+}
+
+var _ hiddenAPIIntf = (*hiddenAPI)(nil)
+
+func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, dexJar android.ModuleOutPath, implementationJar android.Path,
+ uncompressDex bool) android.ModuleOutPath {
+
+ if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ isBootJar := inList(ctx.ModuleName(), ctx.Config().BootJars())
+ if isBootJar || inList(ctx.ModuleName(), config.HiddenAPIExtraAppUsageJars) {
+ // Derive the greylist from classes jar.
+ flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
+ metadataCSV := android.PathForModuleOut(ctx, "hiddenapi", "metadata.csv")
+ hiddenAPIGenerateCSV(ctx, flagsCSV, metadataCSV, implementationJar)
+ h.flagsCSVPath = flagsCSV
+ h.metadataCSVPath = metadataCSV
+ }
+ if isBootJar {
+ hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", ctx.ModuleName()+".jar")
+ h.bootDexJarPath = dexJar
+ hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex)
+ dexJar = hiddenAPIJar
+ }
+ }
+
+ return dexJar
+}
+
+func hiddenAPIGenerateCSV(ctx android.ModuleContext, flagsCSV, metadataCSV android.WritablePath,
+ classesJar android.Path) {
+
+ stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags
ctx.Build(pctx, android.BuildParams{
Rule: hiddenAPIGenerateCSVRule,
@@ -58,7 +107,6 @@
},
})
- hiddenAPISaveCSVOutputs(ctx, flagsCSV, metadataCSV)
}
var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{
@@ -77,10 +125,10 @@
},
}, "flagsCsv", "hiddenapiFlags", "tmpDir", "soongZipFlags")
-func hiddenAPIEncodeDex(ctx android.ModuleContext, output android.WritablePath, dexInput android.WritablePath,
+func hiddenAPIEncodeDex(ctx android.ModuleContext, output android.WritablePath, dexInput android.Path,
uncompressDex bool) {
- flagsCsv := &bootImagePath{ctx.Config().HiddenAPIFlags()}
+ flagsCSV := hiddenAPISingletonPaths(ctx).flags
// The encode dex rule requires unzipping and rezipping the classes.dex files, ensure that if it was uncompressed
// in the input it stays uncompressed in the output.
@@ -104,9 +152,9 @@
Description: "hiddenapi encode dex",
Input: dexInput,
Output: tmpOutput,
- Implicit: flagsCsv,
+ Implicit: flagsCSV,
Args: map[string]string{
- "flagsCsv": flagsCsv.String(),
+ "flagsCsv": flagsCSV.String(),
"tmpDir": tmpDir.String(),
"soongZipFlags": soongZipFlags,
"hiddenapiFlags": hiddenapiFlags,
@@ -116,55 +164,15 @@
if uncompressDex {
TransformZipAlign(ctx, output, tmpOutput)
}
-
- hiddenAPISaveDexInputs(ctx, dexInput)
}
-const hiddenAPIOutputsKey = "hiddenAPIOutputsKey"
-
-var hiddenAPIOutputsLock sync.Mutex
-
-func hiddenAPIGetOutputs(config android.Config) (*android.Paths, *android.Paths, *android.Paths) {
- type threePathsPtrs [3]*android.Paths
- s := config.Once(hiddenAPIOutputsKey, func() interface{} {
- return threePathsPtrs{new(android.Paths), new(android.Paths), new(android.Paths)}
- }).(threePathsPtrs)
- return s[0], s[1], s[2]
+type hiddenAPIPath struct {
+ path string
}
-func hiddenAPISaveCSVOutputs(ctx android.ModuleContext, flagsCSV, metadataCSV android.Path) {
- flagsCSVList, metadataCSVList, _ := hiddenAPIGetOutputs(ctx.Config())
+var _ android.Path = (*hiddenAPIPath)(nil)
- hiddenAPIOutputsLock.Lock()
- defer hiddenAPIOutputsLock.Unlock()
-
- *flagsCSVList = append(*flagsCSVList, flagsCSV)
- *metadataCSVList = append(*metadataCSVList, metadataCSV)
-}
-
-func hiddenAPISaveDexInputs(ctx android.ModuleContext, dexInput android.Path) {
- _, _, dexInputList := hiddenAPIGetOutputs(ctx.Config())
-
- hiddenAPIOutputsLock.Lock()
- defer hiddenAPIOutputsLock.Unlock()
-
- *dexInputList = append(*dexInputList, dexInput)
-}
-
-func init() {
- android.RegisterMakeVarsProvider(pctx, hiddenAPIMakeVars)
-}
-
-func hiddenAPIMakeVars(ctx android.MakeVarsContext) {
- flagsCSVList, metadataCSVList, dexInputList := hiddenAPIGetOutputs(ctx.Config())
-
- export := func(name string, paths *android.Paths) {
- s := paths.Strings()
- sort.Strings(s)
- ctx.Strict(name, strings.Join(s, " "))
- }
-
- export("SOONG_HIDDENAPI_FLAGS", flagsCSVList)
- export("SOONG_HIDDENAPI_GREYLIST_METADATA", metadataCSVList)
- export("SOONG_HIDDENAPI_DEX_INPUTS", dexInputList)
-}
+func (p *hiddenAPIPath) String() string { return p.path }
+func (p *hiddenAPIPath) Ext() string { return filepath.Ext(p.path) }
+func (p *hiddenAPIPath) Base() string { return filepath.Base(p.path) }
+func (p *hiddenAPIPath) Rel() string { return p.path }
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
new file mode 100644
index 0000000..de1bcf5
--- /dev/null
+++ b/java/hiddenapi_singleton.go
@@ -0,0 +1,290 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ android.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+}
+
+type hiddenAPISingletonPathsStruct struct {
+ stubFlags android.OutputPath
+ flags android.OutputPath
+ metadata android.OutputPath
+}
+
+var hiddenAPISingletonPathsKey = android.NewOnceKey("hiddenAPISingletonPathsKey")
+
+// hiddenAPISingletonPaths creates all the paths for singleton files the first time it is called, which may be
+// from a ModuleContext that needs to reference a file that will be created by a singleton rule that hasn't
+// yet been created.
+func hiddenAPISingletonPaths(ctx android.PathContext) hiddenAPISingletonPathsStruct {
+ return ctx.Config().Once(hiddenAPISingletonPathsKey, func() interface{} {
+ return hiddenAPISingletonPathsStruct{
+ stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"),
+ flags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"),
+ metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-greylist.csv"),
+ }
+ }).(hiddenAPISingletonPathsStruct)
+}
+
+func hiddenAPISingletonFactory() android.Singleton {
+ return hiddenAPISingleton{}
+}
+
+type hiddenAPISingleton struct{}
+
+// hiddenAPI singleton rules
+func (hiddenAPISingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true
+ if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ return
+ }
+
+ stubFlagsRule(ctx)
+
+ // These rules depend on files located in frameworks/base, skip them if running in a tree that doesn't have them.
+ if ctx.Config().FrameworksBaseDirExists(ctx) {
+ flagsRule(ctx)
+ metadataRule(ctx)
+ } else {
+ emptyFlagsRule(ctx)
+ }
+}
+
+// stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image
+// modules.
+func stubFlagsRule(ctx android.SingletonContext) {
+ // Public API stubs
+ publicStubModules := []string{
+ "android_stubs_current",
+ "android.test.base.stubs",
+ }
+
+ // System API stubs
+ systemStubModules := []string{
+ "android_system_stubs_current",
+ }
+
+ // Test API stubs
+ testStubModules := []string{
+ "android_test_stubs_current",
+ }
+
+ // Core Platform API stubs
+ corePlatformStubModules := []string{
+ "core.platform.api.stubs",
+ }
+
+ // Allow products to define their own stubs for custom product jars that apps can use.
+ publicStubModules = append(publicStubModules, ctx.Config().ProductHiddenAPIStubs()...)
+ systemStubModules = append(systemStubModules, ctx.Config().ProductHiddenAPIStubsSystem()...)
+ testStubModules = append(testStubModules, ctx.Config().ProductHiddenAPIStubsTest()...)
+
+ publicStubPaths := make(android.Paths, len(publicStubModules))
+ systemStubPaths := make(android.Paths, len(systemStubModules))
+ testStubPaths := make(android.Paths, len(testStubModules))
+ corePlatformStubPaths := make(android.Paths, len(corePlatformStubModules))
+
+ moduleListToPathList := map[*[]string]android.Paths{
+ &publicStubModules: publicStubPaths,
+ &systemStubModules: systemStubPaths,
+ &testStubModules: testStubPaths,
+ &corePlatformStubModules: corePlatformStubPaths,
+ }
+
+ var bootDexJars android.Paths
+
+ ctx.VisitAllModules(func(module android.Module) {
+ // Collect dex jar paths for the modules listed above.
+ if j, ok := module.(Dependency); ok {
+ name := ctx.ModuleName(module)
+ for moduleList, pathList := range moduleListToPathList {
+ if i := android.IndexList(name, *moduleList); i != -1 {
+ pathList[i] = j.DexJar()
+ }
+ }
+ }
+
+ // Collect dex jar paths for modules that had hiddenapi encode called on them.
+ if h, ok := module.(hiddenAPIIntf); ok {
+ if jar := h.bootDexJar(); jar != nil {
+ bootDexJars = append(bootDexJars, jar)
+ }
+ }
+ })
+
+ var missingDeps []string
+ // Ensure all modules were converted to paths
+ for moduleList, pathList := range moduleListToPathList {
+ for i := range pathList {
+ if pathList[i] == nil {
+ if ctx.Config().AllowMissingDependencies() {
+ missingDeps = append(missingDeps, (*moduleList)[i])
+ pathList[i] = android.PathForOutput(ctx, "missing")
+ } else {
+ ctx.Errorf("failed to find dex jar path for module %q",
+ (*moduleList)[i])
+ }
+ }
+ }
+ }
+
+ // Singleton rule which applies hiddenapi on all boot class path dex files.
+ rule := android.NewRuleBuilder()
+
+ outputPath := hiddenAPISingletonPaths(ctx).stubFlags
+ tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
+
+ rule.MissingDeps(missingDeps)
+
+ rule.Command().
+ Tool(pctx.HostBinToolPath(ctx, "hiddenapi").String()).
+ Text("list").
+ FlagForEachInput("--boot-dex=", bootDexJars.Strings()).
+ FlagWithInputList("--public-stub-classpath=", publicStubPaths.Strings(), ":").
+ FlagWithInputList("--public-stub-classpath=", systemStubPaths.Strings(), ":").
+ FlagWithInputList("--public-stub-classpath=", testStubPaths.Strings(), ":").
+ FlagWithInputList("--core-platform-stub-classpath=", corePlatformStubPaths.Strings(), ":").
+ FlagWithOutput("--out-api-flags=", tempPath.String())
+
+ commitChangeForRestat(rule, tempPath, outputPath)
+
+ rule.Build(pctx, ctx, "hiddenAPIStubFlagsFile", "hiddenapi stub flags")
+}
+
+// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
+// the greylists.
+func flagsRule(ctx android.SingletonContext) {
+ var flagsCSV android.Paths
+
+ var greylistIgnoreConflicts android.Path
+
+ ctx.VisitAllModules(func(module android.Module) {
+ if h, ok := module.(hiddenAPIIntf); ok {
+ if csv := h.flagsCSV(); csv != nil {
+ flagsCSV = append(flagsCSV, csv)
+ }
+ } else if ds, ok := module.(*Droidstubs); ok && ctx.ModuleName(module) == "hiddenapi-lists-docs" {
+ greylistIgnoreConflicts = ds.removedDexApiFile
+ }
+ })
+
+ if greylistIgnoreConflicts == nil {
+ ctx.Errorf("failed to find removed_dex_api_filename from hiddenapi-lists-docs module")
+ return
+ }
+
+ rule := android.NewRuleBuilder()
+
+ outputPath := hiddenAPISingletonPaths(ctx).flags
+ tempPath := android.PathForOutput(ctx, outputPath.Rel()+".tmp")
+
+ stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
+
+ rule.Command().
+ Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py").String()).
+ FlagWithInput("--csv ", stubFlags.String()).
+ Inputs(flagsCSV.Strings()).
+ FlagWithInput("--greylist ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt").String()).
+ FlagWithInput("--greylist-ignore-conflicts ",
+ greylistIgnoreConflicts.String()).
+ FlagWithInput("--greylist-max-p ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt").String()).
+ FlagWithInput("--greylist-max-o-ignore-conflicts ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt").String()).
+ FlagWithInput("--blacklist ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt").String()).
+ FlagWithOutput("--output ", tempPath.String())
+
+ commitChangeForRestat(rule, tempPath, outputPath)
+
+ rule.Build(pctx, ctx, "hiddenAPIFlagsFile", "hiddenapi flags")
+}
+
+// emptyFlagsRule creates a rule to build an empty hiddenapi-flags.csv, which is needed by master-art-host builds that
+// have a partial manifest without frameworks/base but still need to build a boot image.
+func emptyFlagsRule(ctx android.SingletonContext) {
+ rule := android.NewRuleBuilder()
+
+ outputPath := hiddenAPISingletonPaths(ctx).flags
+
+ rule.Command().Text("rm").Flag("-f").Output(outputPath.String())
+ rule.Command().Text("touch").Output(outputPath.String())
+
+ rule.Build(pctx, ctx, "emptyHiddenAPIFlagsFile", "empty hiddenapi flags")
+}
+
+// metadataRule creates a rule to build hiddenapi-greylist.csv out of the metadata.csv files generated for boot image
+// modules.
+func metadataRule(ctx android.SingletonContext) {
+ var metadataCSV android.Paths
+
+ ctx.VisitAllModules(func(module android.Module) {
+ if h, ok := module.(hiddenAPIIntf); ok {
+ if csv := h.metadataCSV(); csv != nil {
+ metadataCSV = append(metadataCSV, csv)
+ }
+ }
+ })
+
+ rule := android.NewRuleBuilder()
+
+ outputPath := hiddenAPISingletonPaths(ctx).metadata
+
+ rule.Command().
+ Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/merge_csv.py").String()).
+ Inputs(metadataCSV.Strings()).
+ Text(">").
+ Output(outputPath.String())
+
+ rule.Build(pctx, ctx, "hiddenAPIGreylistMetadataFile", "hiddenapi greylist metadata")
+}
+
+// commitChangeForRestat adds a command to a rule that updates outputPath from tempPath if they are different. It
+// also marks the rule as restat and marks the tempPath as a temporary file that should not be considered an output of
+// the rule.
+func commitChangeForRestat(rule *android.RuleBuilder, tempPath, outputPath android.WritablePath) {
+ rule.Restat()
+ rule.Temporary(tempPath.String())
+ rule.Command().
+ Text("(").
+ Text("if").
+ Text("cmp -s").Input(tempPath.String()).Output(outputPath.String()).Text(";").
+ Text("then").
+ Text("rm").Input(tempPath.String()).Text(";").
+ Text("else").
+ Text("mv").Input(tempPath.String()).Output(outputPath.String()).Text(";").
+ Text("fi").
+ Text(")")
+}
+
+func init() {
+ android.RegisterMakeVarsProvider(pctx, hiddenAPIMakeVars)
+}
+
+// Export paths to Make. INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
+// Both paths are used to call dist-for-goals.
+func hiddenAPIMakeVars(ctx android.MakeVarsContext) {
+ if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+ singletonPaths := hiddenAPISingletonPaths(ctx)
+ ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", singletonPaths.flags.String())
+ ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA", singletonPaths.metadata.String())
+ }
+}
diff --git a/java/java.go b/java/java.go
index 230e8f2..880f920 100644
--- a/java/java.go
+++ b/java/java.go
@@ -36,7 +36,7 @@
android.RegisterModuleType("java_defaults", defaultsFactory)
android.RegisterModuleType("java_library", LibraryFactory)
- android.RegisterModuleType("java_library_static", LibraryFactory)
+ android.RegisterModuleType("java_library_static", LibraryStaticFactory)
android.RegisterModuleType("java_library_host", LibraryHostFactory)
android.RegisterModuleType("java_binary", BinaryFactory)
android.RegisterModuleType("java_binary_host", BinaryHostFactory)
@@ -78,12 +78,11 @@
// list of files that should be excluded from java_resources and java_resource_dirs
Exclude_java_resources []string `android:"arch_variant"`
- // don't build against the default libraries (bootclasspath, legacy-test, core-junit,
- // ext, and framework for device targets)
+ // don't build against the default libraries (bootclasspath, ext, and framework for device
+ // targets)
No_standard_libs *bool
- // don't build against the framework libraries (legacy-test, core-junit,
- // ext, and framework for device targets)
+ // don't build against the framework libraries (ext, and framework for device targets)
No_framework_libs *bool
// list of module-specific flags that will be used for javac compiles
@@ -313,6 +312,7 @@
// expanded Jarjar_rules
expandJarjarRules android.Path
+ hiddenAPI
dexpreopter
}
@@ -331,13 +331,14 @@
ImplementationJars() android.Paths
ResourceJars() android.Paths
ImplementationAndResourcesJars() android.Paths
+ DexJar() android.Path
AidlIncludeDirs() android.Paths
ExportedSdkLibs() []string
}
type SdkLibraryDependency interface {
- HeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths
- ImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths
+ SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths
+ SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths
}
type SrcDependency interface {
@@ -531,7 +532,7 @@
aidlIncludes = append(aidlIncludes,
android.PathsForSource(ctx, j.deviceProperties.Aidl.Include_dirs)...)
- flags := []string{"-b"}
+ flags := []string{}
if aidlPreprocess.Valid() {
flags = append(flags, "-p"+aidlPreprocess.String())
@@ -696,6 +697,15 @@
}
}
switch dep := module.(type) {
+ case SdkLibraryDependency:
+ switch tag {
+ case libTag:
+ deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
+ // names of sdk libs that are directly depended are exported
+ j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
+ default:
+ ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
+ }
case Dependency:
switch tag {
case bootClasspathTag:
@@ -746,15 +756,6 @@
}
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
- case SdkLibraryDependency:
- switch tag {
- case libTag:
- deps.classpath = append(deps.classpath, dep.HeaderJars(ctx, j.sdkVersion())...)
- // names of sdk libs that are directly depended are exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
- default:
- ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
- }
case android.SourceFileProducer:
switch tag {
case libTag:
@@ -1216,18 +1217,8 @@
}
// Hidden API CSV generation and dex encoding
- if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
- isBootJar := inList(ctx.ModuleName(), ctx.Config().BootJars())
- if isBootJar || inList(ctx.ModuleName(), ctx.Config().HiddenAPIExtraAppUsageJars()) {
- // Derive the greylist from classes jar.
- hiddenAPIGenerateCSV(ctx, j.implementationJarFile)
- }
- if isBootJar {
- hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", jarName)
- hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexOutputFile, j.deviceProperties.UncompressDex)
- dexOutputFile = hiddenAPIJar
- }
- }
+ dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, dexOutputFile, j.implementationJarFile,
+ j.deviceProperties.UncompressDex)
// merge dex jar with resources if necessary
if j.resourceJar != nil {
@@ -1247,8 +1238,6 @@
j.dexJarFile = dexOutputFile
// Dexpreopting
- j.dexpreopter.isInstallable = Bool(j.properties.Installable)
- j.dexpreopter.uncompressedDex = j.deviceProperties.UncompressDex
dexOutputFile = j.dexpreopt(ctx, dexOutputFile)
j.maybeStrippedDexJarFile = dexOutputFile
@@ -1365,6 +1354,10 @@
return android.Paths{j.implementationJarFile}
}
+func (j *Module) DexJar() android.Path {
+ return j.dexJarFile
+}
+
func (j *Module) ResourceJars() android.Paths {
if j.resourceJar == nil {
return nil
@@ -1421,19 +1414,29 @@
}
func (j *Library) shouldUncompressDex(ctx android.ModuleContext) bool {
- // Store uncompressed (and do not strip) dex files from boot class path jars that are
- // in an apex.
- if inList(ctx.ModuleName(), ctx.Config().BootJars()) &&
- android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
+ // Store uncompressed (and do not strip) dex files from boot class path jars.
+ if inList(ctx.ModuleName(), ctx.Config().BootJars()) {
return true
}
+
+ // Store uncompressed dex files that are preopted on /system.
+ if !j.dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, j.dexpreopter.installPath)) {
+ return true
+ }
+ if ctx.Config().UncompressPrivAppDex() &&
+ inList(ctx.ModuleName(), ctx.Config().ModulesLoadedByPrivilegedModules()) {
+ return true
+ }
+
return false
}
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", ctx.ModuleName()+".jar")
j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
- j.deviceProperties.UncompressDex = j.shouldUncompressDex(ctx)
+ j.dexpreopter.isInstallable = Bool(j.properties.Installable)
+ j.dexpreopter.uncompressedDex = j.shouldUncompressDex(ctx)
+ j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex
j.compile(ctx)
if (Bool(j.properties.Installable) || ctx.Host()) && !android.DirectlyInAnyApex(ctx, ctx.ModuleName()) {
@@ -1446,6 +1449,17 @@
j.deps(ctx)
}
+// java_library builds and links sources into a `.jar` file for the device, and possibly for the host as well.
+//
+// By default, a java_library has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the device bootclasspath. This jar is not suitable for installing on a device, but can be used
+// as a `static_libs` dependency of another module.
+//
+// Specifying `installable: true` will product a `.jar` file containing `classes.dex` files, suitable for installing on
+// a device.
+//
+// Specifying `host_supported: true` will produce two variants, one compiled against the device bootclasspath and one
+// compiled against the host bootclasspath.
func LibraryFactory() android.Module {
module := &Library{}
@@ -1459,6 +1473,15 @@
return module
}
+// java_library_static is an obsolete alias for java_library.
+func LibraryStaticFactory() android.Module {
+ return LibraryFactory()
+}
+
+// java_library_host builds and links sources into a `.jar` file for the host.
+//
+// A java_library_host has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the host bootclasspath.
func LibraryHostFactory() android.Module {
module := &Library{}
@@ -1517,6 +1540,14 @@
android.ExtractSourcesDeps(ctx, j.testProperties.Data)
}
+// java_test builds a and links sources into a `.jar` file for the device, and possibly for the host as well, and
+// creates an `AndroidTest.xml` file to allow running the test with `atest` or a `TEST_MAPPING` file.
+//
+// By default, a java_test has a single variant that produces a `.jar` file containing `classes.dex` files that were
+// compiled against the device bootclasspath.
+//
+// Specifying `host_supported: true` will produce two variants, one compiled against the device bootclasspath and one
+// compiled against the host bootclasspath.
func TestFactory() android.Module {
module := &Test{}
@@ -1534,6 +1565,11 @@
return module
}
+// java_test_host builds a and links sources into a `.jar` file for the host, and creates an `AndroidTest.xml` file to
+// allow running the test with `atest` or a `TEST_MAPPING` file.
+//
+// A java_test_host has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the host bootclasspath.
func TestHostFactory() android.Module {
module := &Test{}
@@ -1615,6 +1651,14 @@
}
}
+// java_binary builds a `.jar` file and a shell script that executes it for the device, and possibly for the host
+// as well.
+//
+// By default, a java_binary has a single variant that produces a `.jar` file containing `classes.dex` files that were
+// compiled against the device bootclasspath.
+//
+// Specifying `host_supported: true` will produce two variants, one compiled against the device bootclasspath and one
+// compiled against the host bootclasspath.
func BinaryFactory() android.Module {
module := &Binary{}
@@ -1632,6 +1676,10 @@
return module
}
+// java_binary_host builds a `.jar` file and a shell script that executes it for the host.
+//
+// A java_binary_host has a single variant that produces a `.jar` file containing `.class` files that were
+// compiled against the host bootclasspath.
func BinaryHostFactory() android.Module {
module := &Binary{}
@@ -1775,6 +1823,10 @@
return android.Paths{j.combinedClasspathFile}
}
+func (j *Import) DexJar() android.Path {
+ return nil
+}
+
func (j *Import) AidlIncludeDirs() android.Paths {
return nil
}
@@ -1809,6 +1861,13 @@
var _ android.PrebuiltInterface = (*Import)(nil)
+// java_import imports one or more `.jar` files into the build graph as if they were built by a java_library module.
+//
+// By default, a java_import has a single variant that expects a `.jar` file containing `.class` files that were
+// compiled against an Android classpath.
+//
+// Specifying `host_supported: true` will produce two variants, one for use as a dependency of device modules and one
+// for host modules.
func ImportFactory() android.Module {
module := &Import{}
@@ -1819,6 +1878,11 @@
return module
}
+// java_import imports one or more `.jar` files into the build graph as if they were built by a java_library_host
+// module.
+//
+// A java_import_host has a single variant that expects a `.jar` file containing `.class` files that were
+// compiled against a host bootclasspath.
func ImportFactoryHost() android.Module {
module := &Import{}
@@ -1840,9 +1904,37 @@
func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
-func (d *Defaults) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
+// java_defaults provides a set of properties that can be inherited by other java or android modules.
+//
+// A module can use the properties from a java_defaults module using `defaults: ["defaults_module_name"]`. Each
+// property in the defaults module that exists in the depending module will be prepended to the depending module's
+// value for that property.
+//
+// Example:
+//
+// java_defaults {
+// name: "example_defaults",
+// srcs: ["common/**/*.java"],
+// javacflags: ["-Xlint:all"],
+// aaptflags: ["--auto-add-overlay"],
+// }
+//
+// java_library {
+// name: "example",
+// defaults: ["example_defaults"],
+// srcs: ["example/**/*.java"],
+// }
+//
+// is functionally identical to:
+//
+// java_library {
+// name: "example",
+// srcs: [
+// "common/**/*.java",
+// "example/**/*.java",
+// ],
+// javacflags: ["-Xlint:all"],
+// }
func defaultsFactory() android.Module {
return DefaultsFactory()
}
diff --git a/java/java_test.go b/java/java_test.go
index a0b8952..034e905 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -61,7 +61,7 @@
env["ANDROID_JAVA8_HOME"] = "jdk8"
}
config := android.TestArchConfig(buildDir, env)
- config.TestProductVariables.DeviceSystemSdkVersions = &[]string{"14", "15"}
+ config.TestProductVariables.DeviceSystemSdkVersions = []string{"14", "15"}
return config
}
@@ -90,14 +90,14 @@
ctx.RegisterModuleType("droiddoc", android.ModuleFactoryAdaptor(DroiddocFactory))
ctx.RegisterModuleType("droiddoc_host", android.ModuleFactoryAdaptor(DroiddocHostFactory))
ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(ExportedDroiddocDirFactory))
- ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(sdkLibraryFactory))
- ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(prebuiltApisFactory))
+ ctx.RegisterModuleType("java_sdk_library", android.ModuleFactoryAdaptor(SdkLibraryFactory))
+ ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(PrebuiltApisFactory))
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("prebuilt_apis", prebuiltApisMutator).Parallel()
- ctx.TopDown("java_sdk_library", sdkLibraryMutator).Parallel()
+ ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
+ ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()
})
ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
ctx.RegisterPreSingletonType("sdk", android.SingletonFactoryAdaptor(sdkSingletonFactory))
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index c11e010..49cc931 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -30,10 +30,10 @@
// It also creates <module>-api.<scope>.latest for the lastest <ver>.
//
func init() {
- android.RegisterModuleType("prebuilt_apis", prebuiltApisFactory)
+ android.RegisterModuleType("prebuilt_apis", PrebuiltApisFactory)
android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("prebuilt_apis", prebuiltApisMutator).Parallel()
+ ctx.TopDown("prebuilt_apis", PrebuiltApisMutator).Parallel()
})
}
@@ -47,10 +47,6 @@
properties prebuiltApisProperties
}
-func (module *prebuiltApis) DepsMutator(ctx android.BottomUpMutatorContext) {
- // no need to implement
-}
-
func (module *prebuiltApis) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// no need to implement
}
@@ -180,14 +176,14 @@
}
}
-func prebuiltApisMutator(mctx android.TopDownMutatorContext) {
+func PrebuiltApisMutator(mctx android.TopDownMutatorContext) {
if _, ok := mctx.Module().(*prebuiltApis); ok {
prebuiltApiFiles(mctx)
prebuiltSdkStubs(mctx)
}
}
-func prebuiltApisFactory() android.Module {
+func PrebuiltApisFactory() android.Module {
module := &prebuiltApis{}
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
diff --git a/java/sdk.go b/java/sdk.go
index 988610f..0959be7 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -28,7 +28,7 @@
android.RegisterPreSingletonType("sdk", sdkSingletonFactory)
}
-const sdkSingletonKey = "sdkSingletonKey"
+var sdkSingletonKey = android.NewOnceKey("sdkSingletonKey")
type sdkContext interface {
// sdkVersion eturns the sdk_version property of the current module, or an empty string if it is not set.
diff --git a/java/sdk_library.go b/java/sdk_library.go
index ca3131c..f2df49b 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -42,6 +42,10 @@
name string
}
+type syspropLibraryInterface interface {
+ SyspropJavaModule() *SdkLibrary
+}
+
var (
publicApiStubsTag = dependencyTag{name: "public"}
systemApiStubsTag = dependencyTag{name: "system"}
@@ -74,10 +78,10 @@
// 2) HTML generation
func init() {
- android.RegisterModuleType("java_sdk_library", sdkLibraryFactory)
+ android.RegisterModuleType("java_sdk_library", SdkLibraryFactory)
android.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("java_sdk_library", sdkLibraryMutator).Parallel()
+ ctx.TopDown("java_sdk_library", SdkLibraryMutator).Parallel()
})
android.RegisterMakeVarsProvider(pctx, func(ctx android.MakeVarsContext) {
@@ -100,7 +104,13 @@
// list of package names that must be hidden from the API
Hidden_api_packages []string
- // Additional droiddoc options
+ // local files that are used within user customized droiddoc options.
+ Droiddoc_option_files []string
+
+ // additional droiddoc options
+ // Available variables for substitution:
+ //
+ // $(location <label>): the path to the droiddoc_option_files with name <label>
Droiddoc_options []string
// the java library (in classpath) for documentation that provides java srcs and srcjars.
@@ -127,7 +137,7 @@
//Html_doc *bool
}
-type sdkLibrary struct {
+type SdkLibrary struct {
Library
sdkLibraryProperties sdkLibraryProperties
@@ -145,7 +155,10 @@
testApiFilePath android.Path
}
-func (module *sdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+var _ Dependency = (*SdkLibrary)(nil)
+var _ SdkLibraryDependency = (*SdkLibrary)(nil)
+
+func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
// Add dependencies to the stubs library
ctx.AddVariationDependencies(nil, publicApiStubsTag, module.stubsName(apiScopePublic))
ctx.AddVariationDependencies(nil, publicApiFileTag, module.docsName(apiScopePublic))
@@ -160,7 +173,7 @@
module.Library.deps(ctx)
}
-func (module *sdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
module.Library.GenerateAndroidBuildActions(ctx)
// Record the paths to the header jars of the library (stubs and impl).
@@ -198,7 +211,7 @@
})
}
-func (module *sdkLibrary) AndroidMk() android.AndroidMkData {
+func (module *SdkLibrary) AndroidMk() android.AndroidMkData {
data := module.Library.AndroidMk()
data.Required = append(data.Required, module.xmlFileName())
@@ -258,7 +271,7 @@
}
// Module name of the stubs library
-func (module *sdkLibrary) stubsName(apiScope apiScope) string {
+func (module *SdkLibrary) stubsName(apiScope apiScope) string {
stubsName := module.BaseModuleName() + sdkStubsLibrarySuffix
switch apiScope {
case apiScopeSystem:
@@ -270,7 +283,7 @@
}
// Module name of the docs
-func (module *sdkLibrary) docsName(apiScope apiScope) string {
+func (module *SdkLibrary) docsName(apiScope apiScope) string {
docsName := module.BaseModuleName() + sdkDocsSuffix
switch apiScope {
case apiScopeSystem:
@@ -282,12 +295,12 @@
}
// Module name of the runtime implementation library
-func (module *sdkLibrary) implName() string {
+func (module *SdkLibrary) implName() string {
return module.BaseModuleName()
}
// File path to the runtime implementation library
-func (module *sdkLibrary) implPath() string {
+func (module *SdkLibrary) implPath() string {
partition := "system"
if module.SocSpecific() {
partition = "vendor"
@@ -300,14 +313,14 @@
}
// Module name of the XML file for the lib
-func (module *sdkLibrary) xmlFileName() string {
+func (module *SdkLibrary) xmlFileName() string {
return module.BaseModuleName() + sdkXmlFileSuffix
}
// SDK version that the stubs library is built against. Note that this is always
// *current. Older stubs library built with a numberd SDK version is created from
// the prebuilt jar.
-func (module *sdkLibrary) sdkVersion(apiScope apiScope) string {
+func (module *SdkLibrary) sdkVersion(apiScope apiScope) string {
switch apiScope {
case apiScopePublic:
return "current"
@@ -323,7 +336,7 @@
// $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated
// api file for the current source
// TODO: remove this when apicheck is done in soong
-func (module *sdkLibrary) apiTagName(apiScope apiScope) string {
+func (module *SdkLibrary) apiTagName(apiScope apiScope) string {
apiTagName := strings.Replace(strings.ToUpper(module.BaseModuleName()), ".", "_", -1)
switch apiScope {
case apiScopeSystem:
@@ -334,7 +347,7 @@
return apiTagName
}
-func (module *sdkLibrary) latestApiFilegroupName(apiScope apiScope) string {
+func (module *SdkLibrary) latestApiFilegroupName(apiScope apiScope) string {
name := ":" + module.BaseModuleName() + ".api."
switch apiScope {
case apiScopePublic:
@@ -348,7 +361,7 @@
return name
}
-func (module *sdkLibrary) latestRemovedApiFilegroupName(apiScope apiScope) string {
+func (module *SdkLibrary) latestRemovedApiFilegroupName(apiScope apiScope) string {
name := ":" + module.BaseModuleName() + "-removed.api."
switch apiScope {
case apiScopePublic:
@@ -363,7 +376,7 @@
}
// Creates a static java library that has API stubs
-func (module *sdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) {
+func (module *SdkLibrary) createStubsLibrary(mctx android.TopDownMutatorContext, apiScope apiScope) {
props := struct {
Name *string
Srcs []string
@@ -422,7 +435,7 @@
// Creates a droiddoc module that creates stubs source files from the given full source
// files
-func (module *sdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) {
+func (module *SdkLibrary) createDocs(mctx android.TopDownMutatorContext, apiScope apiScope) {
props := struct {
Name *string
Srcs []string
@@ -431,6 +444,7 @@
Srcs_lib_whitelist_dirs []string
Srcs_lib_whitelist_pkgs []string
Libs []string
+ Arg_files []string
Args *string
Api_tag_name *string
Api_filename *string
@@ -478,6 +492,7 @@
case apiScopeTest:
droiddocArgs = droiddocArgs + " -showAnnotation android.annotation.TestApi"
}
+ props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
props.Args = proptools.StringPtr(droiddocArgs)
// List of APIs identified from the provided source files are created. They are later
@@ -517,7 +532,7 @@
}
// Creates the xml file that publicizes the runtime library
-func (module *sdkLibrary) createXmlFile(mctx android.TopDownMutatorContext) {
+func (module *SdkLibrary) createXmlFile(mctx android.TopDownMutatorContext) {
template := `
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project
@@ -576,7 +591,7 @@
mctx.CreateModule(android.ModuleFactoryAdaptor(android.PrebuiltEtcFactory), &etcProps)
}
-func (module *sdkLibrary) PrebuiltJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *SdkLibrary) PrebuiltJars(ctx android.BaseContext, sdkVersion string) android.Paths {
var api, v string
if sdkVersion == "" {
api = "system"
@@ -596,7 +611,7 @@
}
// to satisfy SdkLibraryDependency interface
-func (module *sdkLibrary) HeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseContext, sdkVersion string) android.Paths {
// This module is just a wrapper for the stubs.
if ctx.Config().UnbundledBuildPrebuiltSdks() {
return module.PrebuiltJars(ctx, sdkVersion)
@@ -612,7 +627,7 @@
}
// to satisfy SdkLibraryDependency interface
-func (module *sdkLibrary) ImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
+func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseContext, sdkVersion string) android.Paths {
// This module is just a wrapper for the stubs.
if ctx.Config().UnbundledBuildPrebuiltSdks() {
return module.PrebuiltJars(ctx, sdkVersion)
@@ -627,8 +642,10 @@
}
}
+var javaSdkLibrariesKey = android.NewOnceKey("javaSdkLibraries")
+
func javaSdkLibraries(config android.Config) *[]string {
- return config.Once("javaSdkLibraries", func() interface{} {
+ return config.Once(javaSdkLibrariesKey, func() interface{} {
return &[]string{}
}).(*[]string)
}
@@ -636,42 +653,47 @@
// For a java_sdk_library module, create internal modules for stubs, docs,
// runtime libs and xml file. If requested, the stubs and docs are created twice
// once for public API level and once for system API level
-func sdkLibraryMutator(mctx android.TopDownMutatorContext) {
- if module, ok := mctx.Module().(*sdkLibrary); ok {
- if module.Library.Module.properties.Srcs == nil {
- mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
- }
-
- if module.sdkLibraryProperties.Api_packages == nil {
- mctx.PropertyErrorf("api_packages", "java_sdk_library must specify api_packages")
- }
- // for public API stubs
- module.createStubsLibrary(mctx, apiScopePublic)
- module.createDocs(mctx, apiScopePublic)
-
- if !Bool(module.properties.No_standard_libs) {
- // for system API stubs
- module.createStubsLibrary(mctx, apiScopeSystem)
- module.createDocs(mctx, apiScopeSystem)
-
- // for test API stubs
- module.createStubsLibrary(mctx, apiScopeTest)
- module.createDocs(mctx, apiScopeTest)
-
- // for runtime
- module.createXmlFile(mctx)
- }
-
- // record java_sdk_library modules so that they are exported to make
- javaSdkLibraries := javaSdkLibraries(mctx.Config())
- javaSdkLibrariesLock.Lock()
- defer javaSdkLibrariesLock.Unlock()
- *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
+func SdkLibraryMutator(mctx android.TopDownMutatorContext) {
+ if module, ok := mctx.Module().(*SdkLibrary); ok {
+ module.createInternalModules(mctx)
+ } else if module, ok := mctx.Module().(syspropLibraryInterface); ok {
+ module.SyspropJavaModule().createInternalModules(mctx)
}
}
-func sdkLibraryFactory() android.Module {
- module := &sdkLibrary{}
+func (module *SdkLibrary) createInternalModules(mctx android.TopDownMutatorContext) {
+ if module.Library.Module.properties.Srcs == nil {
+ mctx.PropertyErrorf("srcs", "java_sdk_library must specify srcs")
+ }
+
+ if module.sdkLibraryProperties.Api_packages == nil {
+ mctx.PropertyErrorf("api_packages", "java_sdk_library must specify api_packages")
+ }
+ // for public API stubs
+ module.createStubsLibrary(mctx, apiScopePublic)
+ module.createDocs(mctx, apiScopePublic)
+
+ if !Bool(module.properties.No_standard_libs) {
+ // for system API stubs
+ module.createStubsLibrary(mctx, apiScopeSystem)
+ module.createDocs(mctx, apiScopeSystem)
+
+ // for test API stubs
+ module.createStubsLibrary(mctx, apiScopeTest)
+ module.createDocs(mctx, apiScopeTest)
+
+ // for runtime
+ module.createXmlFile(mctx)
+ }
+
+ // record java_sdk_library modules so that they are exported to make
+ javaSdkLibraries := javaSdkLibraries(mctx.Config())
+ javaSdkLibrariesLock.Lock()
+ defer javaSdkLibrariesLock.Unlock()
+ *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
+}
+
+func (module *SdkLibrary) InitSdkLibraryProperties() {
module.AddProperties(
&module.sdkLibraryProperties,
&module.Library.Module.properties,
@@ -682,7 +704,11 @@
module.Library.Module.properties.Installable = proptools.BoolPtr(true)
module.Library.Module.deviceProperties.IsSDKLibrary = true
+}
+func SdkLibraryFactory() android.Module {
+ module := &SdkLibrary{}
+ module.InitSdkLibraryProperties()
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
diff --git a/java/support_libraries.go b/java/support_libraries.go
index 320afae..5a72f41 100644
--- a/java/support_libraries.go
+++ b/java/support_libraries.go
@@ -28,9 +28,8 @@
func supportLibrariesMakeVarsProvider(ctx android.MakeVarsContext) {
var supportAars, supportJars []string
- sctx := ctx.SingletonContext()
- sctx.VisitAllModules(func(module android.Module) {
- dir := sctx.ModuleDir(module)
+ ctx.VisitAllModules(func(module android.Module) {
+ dir := ctx.ModuleDir(module)
switch {
case strings.HasPrefix(dir, "prebuilts/sdk/current/extras"),
dir == "prebuilts/sdk/current/androidx",
@@ -43,7 +42,7 @@
return
}
- name := sctx.ModuleName(module)
+ name := ctx.ModuleName(module)
if strings.HasSuffix(name, "-nodeps") {
return
}
@@ -54,7 +53,7 @@
case *Library, *Import:
supportJars = append(supportJars, name)
default:
- sctx.ModuleErrorf(module, "unknown module type %t", module)
+ ctx.ModuleErrorf(module, "unknown module type %t", module)
}
})
diff --git a/phony/phony.go b/phony/phony.go
index 0c62e8a..e8a6550 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -38,9 +38,6 @@
return module
}
-func (p *phony) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func (p *phony) GenerateAndroidBuildActions(ctx android.ModuleContext) {
p.requiredModuleNames = ctx.RequiredModuleNames()
if len(p.requiredModuleNames) == 0 {
diff --git a/python/defaults.go b/python/defaults.go
index 641aca4..dba23a7 100644
--- a/python/defaults.go
+++ b/python/defaults.go
@@ -30,9 +30,6 @@
func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
-func (d *Defaults) DepsMutator(ctx android.BottomUpMutatorContext) {
-}
-
func defaultsFactory() android.Module {
return DefaultsFactory()
}
diff --git a/python/tests/Android.bp b/python/tests/Android.bp
new file mode 100644
index 0000000..1f4305c
--- /dev/null
+++ b/python/tests/Android.bp
@@ -0,0 +1,32 @@
+// 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.
+
+python_test_host {
+ name: "par_test",
+ main: "par_test.py",
+ srcs: [
+ "par_test.py",
+ "testpkg/par_test.py",
+ ],
+
+ version: {
+ py2: {
+ enabled: true,
+ embedded_launcher: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+}
diff --git a/python/tests/par_test.py b/python/tests/par_test.py
new file mode 100644
index 0000000..1fafe0f
--- /dev/null
+++ b/python/tests/par_test.py
@@ -0,0 +1,50 @@
+# 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.
+
+import os
+import site
+import sys
+
+# This file checks the visible python state against expected values when run
+# inside a hermetic par file.
+
+failed = False
+def assert_equal(what, a, b):
+ global failed
+ if a != b:
+ print("Expected %s('%s') == '%s'" % (what, a, b))
+ failed = True
+
+assert_equal("__name__", __name__, "__main__")
+assert_equal("os.path.basename(__file__)", os.path.basename(__file__), "par_test.py")
+
+archive = os.path.dirname(__file__)
+
+assert_equal("__package__", __package__, "")
+assert_equal("sys.argv[0]", sys.argv[0], archive)
+assert_equal("sys.executable", sys.executable, None)
+assert_equal("sys.exec_prefix", sys.exec_prefix, archive)
+assert_equal("sys.prefix", sys.prefix, archive)
+assert_equal("__loader__.archive", __loader__.archive, archive)
+assert_equal("site.ENABLE_USER_SITE", site.ENABLE_USER_SITE, None)
+
+assert_equal("len(sys.path)", len(sys.path), 3)
+assert_equal("sys.path[0]", sys.path[0], archive)
+assert_equal("sys.path[1]", sys.path[1], os.path.join(archive, "internal"))
+assert_equal("sys.path[2]", sys.path[2], os.path.join(archive, "internal", "stdlib"))
+
+if failed:
+ sys.exit(1)
+
+import testpkg.par_test
diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh
new file mode 100755
index 0000000..a319558
--- /dev/null
+++ b/python/tests/runtest.sh
@@ -0,0 +1,39 @@
+#!/bin/bash -e
+#
+# 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 just a helper to run the tests under a few different environments
+#
+
+if [ -z $ANDROID_HOST_OUT ]; then
+ echo "Must be run after running lunch"
+ exit 1
+fi
+
+if [ ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ]; then
+ echo "Run 'm par_test' first"
+ exit 1
+fi
+
+export LD_LIBRARY_PATH=$ANDROID_HOST_OUT/lib64
+
+set -x
+
+PYTHONHOME= PYTHONPATH= $ANDROID_HOST_OUT/nativetest64/par_test/par_test
+PYTHONHOME=/usr $ANDROID_HOST_OUT/nativetest64/par_test/par_test
+PYTHONPATH=/usr $ANDROID_HOST_OUT/nativetest64/par_test/par_test
+
+echo "Passed!"
diff --git a/python/tests/testpkg/par_test.py b/python/tests/testpkg/par_test.py
new file mode 100644
index 0000000..22dd095
--- /dev/null
+++ b/python/tests/testpkg/par_test.py
@@ -0,0 +1,37 @@
+# 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.
+
+import os
+import sys
+
+# This file checks the visible python state against expected values when run
+# inside a hermetic par file.
+
+failed = False
+def assert_equal(what, a, b):
+ global failed
+ if a != b:
+ print("Expected %s('%s') == '%s'" % (what, a, b))
+ failed = True
+
+archive = sys.modules["__main__"].__loader__.archive
+
+assert_equal("__name__", __name__, "testpkg.par_test")
+assert_equal("__file__", __file__, os.path.join(archive, "testpkg/par_test.py"))
+assert_equal("__package__", __package__, "testpkg")
+assert_equal("__loader__.archive", __loader__.archive, archive)
+assert_equal("__loader__.prefix", __loader__.prefix, "testpkg/")
+
+if failed:
+ sys.exit(1)
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/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 917f55b..83868e6 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -63,8 +63,12 @@
help='manifest is for a package built against the platform')
parser.add_argument('--use-embedded-dex', dest='use_embedded_dex', action='store_true',
help=('specify if the app wants to use embedded dex and avoid extracted,'
- 'locally compiled code. Should not be conflict if already declared '
+ 'locally compiled code. Must not conflict if already declared '
'in the manifest.'))
+ parser.add_argument('--extract-native-libs', dest='extract_native_libs',
+ default=None, type=lambda x: (str(x).lower() == 'true'),
+ help=('specify if the app wants to use embedded native libraries. Must not conflict '
+ 'if already declared in the manifest.'))
parser.add_argument('input', help='input AndroidManifest.xml file')
parser.add_argument('output', help='output AndroidManifest.xml file')
return parser.parse_args()
@@ -295,6 +299,30 @@
raise RuntimeError('existing attribute mismatches the option of --use-embedded-dex')
+def add_extract_native_libs(doc, extract_native_libs):
+ manifest = parse_manifest(doc)
+ elems = get_children_with_tag(manifest, 'application')
+ application = elems[0] if len(elems) == 1 else None
+ if len(elems) > 1:
+ raise RuntimeError('found multiple <application> tags')
+ elif not elems:
+ application = doc.createElement('application')
+ indent = get_indent(manifest.firstChild, 1)
+ first = manifest.firstChild
+ manifest.insertBefore(doc.createTextNode(indent), first)
+ manifest.insertBefore(application, first)
+
+ value = str(extract_native_libs).lower()
+ attr = application.getAttributeNodeNS(android_ns, 'extractNativeLibs')
+ if attr is None:
+ attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs')
+ attr.value = value
+ application.setAttributeNode(attr)
+ elif attr.value != value:
+ raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' %
+ (attr.value, value))
+
+
def write_xml(f, doc):
f.write('<?xml version="1.0" encoding="utf-8"?>\n')
for node in doc.childNodes:
@@ -325,6 +353,9 @@
if args.use_embedded_dex:
add_use_embedded_dex(doc)
+ if args.extract_native_libs is not None:
+ add_extract_native_libs(doc, args.extract_native_libs)
+
with open(args.output, 'wb') as f:
write_xml(f, doc)
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 1d8de55..4ad9afa 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -381,5 +381,48 @@
manifest_input = self.manifest_tmpl % self.use_embedded_dex('false')
self.assertRaises(RuntimeError, self.run_test, manifest_input)
+
+class AddExtractNativeLibsTest(unittest.TestCase):
+ """Unit tests for add_extract_native_libs function."""
+
+ def run_test(self, input_manifest, value):
+ doc = minidom.parseString(input_manifest)
+ manifest_fixer.add_extract_native_libs(doc, value)
+ output = StringIO.StringIO()
+ manifest_fixer.write_xml(output, doc)
+ return output.getvalue()
+
+ manifest_tmpl = (
+ '<?xml version="1.0" encoding="utf-8"?>\n'
+ '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
+ ' <application%s/>\n'
+ '</manifest>\n')
+
+ def extract_native_libs(self, value):
+ return ' android:extractNativeLibs="%s"' % value
+
+ def test_set_true(self):
+ manifest_input = self.manifest_tmpl % ''
+ expected = self.manifest_tmpl % self.extract_native_libs('true')
+ output = self.run_test(manifest_input, True)
+ self.assertEqual(output, expected)
+
+ def test_set_false(self):
+ manifest_input = self.manifest_tmpl % ''
+ expected = self.manifest_tmpl % self.extract_native_libs('false')
+ output = self.run_test(manifest_input, False)
+ self.assertEqual(output, expected)
+
+ def test_match(self):
+ manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
+ expected = manifest_input
+ output = self.run_test(manifest_input, True)
+ self.assertEqual(output, expected)
+
+ def test_conflict(self):
+ manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
+ self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
+
+
if __name__ == '__main__':
unittest.main()
diff --git a/scripts/strip.sh b/scripts/strip.sh
index d826e57..bedc527 100755
--- a/scripts/strip.sh
+++ b/scripts/strip.sh
@@ -27,7 +27,7 @@
# --add-gnu-debuglink
# --keep-mini-debug-info
# --keep-symbols
-# --use-llvm-strip
+# --use-gnu-strip
set -o pipefail
@@ -40,12 +40,12 @@
--add-gnu-debuglink Add a gnu-debuglink section to out-file
--keep-mini-debug-info Keep compressed debug info in out-file
--keep-symbols Keep symbols in out-file
- --use-llvm-strip Use llvm-{strip,objcopy} instead of strip/objcopy
+ --use-gnu-strip Use strip/objcopy instead of llvm-{strip,objcopy}
EOF
exit 1
}
-# With --use-llvm-strip, GNU strip is replaced with llvm-strip to work around
+# Without --use-gnu-strip, GNU strip is replaced with llvm-strip to work around
# old GNU strip bug on lld output files, b/80093681.
# Similary, calls to objcopy are replaced with llvm-objcopy,
# with some exceptions.
@@ -53,7 +53,7 @@
do_strip() {
# ${CROSS_COMPILE}strip --strip-all does not strip .ARM.attributes,
# so we tell llvm-strip to keep it too.
- if [ ! -z "${use_llvm_strip}" ]; then
+ if [ -z "${use_gnu_strip}" ]; then
"${CLANG_BIN}/llvm-strip" --strip-all -keep-section=.ARM.attributes "${infile}" -o "${outfile}.tmp"
else
"${CROSS_COMPILE}strip" --strip-all "${infile}" -o "${outfile}.tmp"
@@ -61,10 +61,8 @@
}
do_strip_keep_symbols() {
- # Maybe we should replace this objcopy with llvm-objcopy, but
- # we have not found a use case that is broken by objcopy yet.
REMOVE_SECTIONS=`"${CROSS_COMPILE}readelf" -S "${infile}" | awk '/.debug_/ {print "--remove-section " $2}' | xargs`
- if [ ! -z "${use_llvm_strip}" ]; then
+ if [ -z "${use_gnu_strip}" ]; then
"${CLANG_BIN}/llvm-objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
else
"${CROSS_COMPILE}objcopy" "${infile}" "${outfile}.tmp" ${REMOVE_SECTIONS}
@@ -74,7 +72,7 @@
do_strip_keep_mini_debug_info() {
rm -f "${outfile}.dynsyms" "${outfile}.funcsyms" "${outfile}.keep_symbols" "${outfile}.debug" "${outfile}.mini_debuginfo" "${outfile}.mini_debuginfo.xz"
local fail=
- if [ ! -z "${use_llvm_strip}" ]; then
+ if [ -z "${use_gnu_strip}" ]; then
"${CLANG_BIN}/llvm-strip" --strip-all -keep-section=.ARM.attributes -remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true
else
"${CROSS_COMPILE}strip" --strip-all -R .comment "${infile}" -o "${outfile}.tmp" || fail=true
@@ -93,7 +91,7 @@
"${CROSS_COMPILE}objcopy" -S --remove-section .gdb_index --remove-section .comment --keep-symbols="${outfile}.keep_symbols" "${outfile}.mini_debuginfo"
"${CROSS_COMPILE}objcopy" --rename-section saved_debug_frame=.debug_frame "${outfile}.mini_debuginfo"
"${XZ}" "${outfile}.mini_debuginfo"
- if [ ! -z "${use_llvm_strip}" ]; then
+ if [ -z "${use_gnu_strip}" ]; then
"${CLANG_BIN}/llvm-objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
else
"${CROSS_COMPILE}objcopy" --add-section .gnu_debugdata="${outfile}.mini_debuginfo.xz" "${outfile}.tmp"
@@ -105,7 +103,7 @@
}
do_add_gnu_debuglink() {
- if [ ! -z "${use_llvm_strip}" ]; then
+ if [ -z "${use_gnu_strip}" ]; then
"${CLANG_BIN}/llvm-objcopy" --add-gnu-debuglink="${infile}" "${outfile}.tmp"
else
"${CROSS_COMPILE}objcopy" --add-gnu-debuglink="${infile}" "${outfile}.tmp"
@@ -122,7 +120,7 @@
add-gnu-debuglink) add_gnu_debuglink=true ;;
keep-mini-debug-info) keep_mini_debug_info=true ;;
keep-symbols) keep_symbols=true ;;
- use-llvm-strip) use_llvm_strip=true ;;
+ use-gnu-strip) use_gnu_strip=true ;;
*) echo "Unknown option --${OPTARG}"; usage ;;
esac;;
?) usage ;;
@@ -172,7 +170,7 @@
rm -f "${outfile}"
mv "${outfile}.tmp" "${outfile}"
-if [ ! -z "${use_llvm_strip}" ]; then
+if [ -z "${use_gnu_strip}" ]; then
USED_STRIP_OBJCOPY="${CLANG_BIN}/llvm-strip ${CLANG_BIN}/llvm-objcopy"
else
USED_STRIP_OBJCOPY="${CROSS_COMPILE}strip"
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
new file mode 100644
index 0000000..4069e78
--- /dev/null
+++ b/sysprop/sysprop_library.go
@@ -0,0 +1,130 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sysprop
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/java"
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
+type syspropLibrary struct {
+ java.SdkLibrary
+
+ commonProperties commonProperties
+ syspropLibraryProperties syspropLibraryProperties
+}
+
+type syspropLibraryProperties struct {
+ // Determine who owns this sysprop library. Possible values are
+ // "Platform", "Vendor", or "Odm"
+ Property_owner string
+ Api_packages []string
+}
+
+type commonProperties struct {
+ Srcs []string
+ Recovery *bool
+ Vendor_available *bool
+}
+
+var (
+ Bool = proptools.Bool
+ syspropCcTag = dependencyTag{name: "syspropCc"}
+)
+
+func init() {
+ android.RegisterModuleType("sysprop_library", syspropLibraryFactory)
+}
+
+func (m *syspropLibrary) CcModuleName() string {
+ return "lib" + m.Name()
+}
+
+func (m *syspropLibrary) SyspropJavaModule() *java.SdkLibrary {
+ return &m.SdkLibrary
+}
+
+func syspropLibraryFactory() android.Module {
+ m := &syspropLibrary{}
+
+ m.AddProperties(
+ &m.commonProperties,
+ &m.syspropLibraryProperties,
+ )
+ m.InitSdkLibraryProperties()
+ android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, "common")
+ android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
+
+ return m
+}
+
+func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
+ if m.syspropLibraryProperties.Api_packages == nil {
+ ctx.PropertyErrorf("api_packages", "sysprop_library must specify api_packages")
+ }
+
+ socSpecific := ctx.SocSpecific()
+ deviceSpecific := ctx.DeviceSpecific()
+ productSpecific := ctx.ProductSpecific()
+
+ owner := m.syspropLibraryProperties.Property_owner
+
+ switch owner {
+ case "Platform":
+ // Every partition can access platform-defined properties
+ break
+ case "Vendor":
+ // System can't access vendor's properties
+ if !socSpecific && !deviceSpecific && !productSpecific {
+ ctx.ModuleErrorf("None of soc_specific, device_specific, product_specific is true. " +
+ "System can't access sysprop_library owned by Vendor")
+ }
+ case "Odm":
+ // Only vendor can access Odm-defined properties
+ if !socSpecific && !deviceSpecific {
+ ctx.ModuleErrorf("Neither soc_speicifc nor device_specific is true. " +
+ "Odm-defined properties should be accessed only in Vendor or Odm")
+ }
+ default:
+ ctx.PropertyErrorf("property_owner",
+ "Unknown value %s: must be one of Platform, Vendor or Odm", owner)
+ }
+
+ ccProps := struct {
+ Name *string
+ Soc_specific *bool
+ Device_specific *bool
+ Product_specific *bool
+ Sysprop struct {
+ Platform *bool
+ }
+ }{}
+
+ ccProps.Name = proptools.StringPtr(m.CcModuleName())
+ ccProps.Soc_specific = proptools.BoolPtr(socSpecific)
+ ccProps.Device_specific = proptools.BoolPtr(deviceSpecific)
+ ccProps.Product_specific = proptools.BoolPtr(productSpecific)
+ ccProps.Sysprop.Platform = proptools.BoolPtr(owner == "Platform")
+
+ ctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &m.commonProperties, &ccProps)
+}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
new file mode 100644
index 0000000..92e0af4
--- /dev/null
+++ b/sysprop/sysprop_test.go
@@ -0,0 +1,380 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sysprop
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/java"
+
+ "fmt"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+
+ "github.com/google/blueprint/proptools"
+)
+
+var buildDir string
+
+func setUp() {
+ var err error
+ buildDir, err = ioutil.TempDir("", "soong_sysprop_test")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func tearDown() {
+ os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+ run := func() int {
+ setUp()
+ defer tearDown()
+
+ return m.Run()
+ }
+
+ os.Exit(run())
+}
+
+func testContext(config android.Config, bp string,
+ fs map[string][]byte) *android.TestContext {
+
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(java.AndroidAppFactory))
+ ctx.RegisterModuleType("droiddoc_template", android.ModuleFactoryAdaptor(java.ExportedDroiddocDirFactory))
+ ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(java.LibraryFactory))
+ ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(java.SystemModulesFactory))
+ ctx.RegisterModuleType("prebuilt_apis", android.ModuleFactoryAdaptor(java.PrebuiltApisFactory))
+ ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("load_hooks", android.LoadHookMutator).Parallel()
+ })
+ ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
+ ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("prebuilt_apis", java.PrebuiltApisMutator).Parallel()
+ ctx.TopDown("java_sdk_library", java.SdkLibraryMutator).Parallel()
+ })
+
+ ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+ ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+ ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(cc.LlndkLibraryFactory))
+ ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("image", cc.ImageMutator).Parallel()
+ ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+ ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
+ ctx.BottomUp("version", cc.VersionMutator).Parallel()
+ ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+ ctx.BottomUp("sysprop", cc.SyspropMutator).Parallel()
+ })
+
+ ctx.RegisterModuleType("sysprop_library", android.ModuleFactoryAdaptor(syspropLibraryFactory))
+
+ ctx.Register()
+
+ extraModules := []string{
+ "core-lambda-stubs",
+ "framework",
+ "ext",
+ "updatable_media_stubs",
+
+ "android_stubs_current",
+ "android_system_stubs_current",
+ "android_test_stubs_current",
+ "core.current.stubs",
+ "core.platform.api.stubs",
+ }
+
+ for _, extra := range extraModules {
+ bp += fmt.Sprintf(`
+ java_library {
+ name: "%s",
+ srcs: ["a.java"],
+ no_standard_libs: true,
+ sdk_version: "core_current",
+ system_modules: "core-platform-api-stubs-system-modules",
+ }
+ `, extra)
+ }
+
+ bp += `
+ android_app {
+ name: "framework-res",
+ no_framework_libs: true,
+ }
+ `
+
+ systemModules := []string{
+ "core-system-modules",
+ "core-platform-api-stubs-system-modules",
+ "android_stubs_current_system_modules",
+ "android_system_stubs_current_system_modules",
+ "android_test_stubs_current_system_modules",
+ }
+
+ for _, extra := range systemModules {
+ bp += fmt.Sprintf(`
+ java_system_modules {
+ name: "%s",
+ }
+ `, extra)
+ }
+
+ bp += cc.GatherRequiredDepsForTest(android.Android)
+
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ "a.java": nil,
+ "b.java": nil,
+ "c.java": nil,
+ "d.cpp": nil,
+ "api/current.txt": nil,
+ "api/removed.txt": nil,
+ "api/system-current.txt": nil,
+ "api/system-removed.txt": nil,
+ "api/test-current.txt": nil,
+ "api/test-removed.txt": nil,
+
+ "prebuilts/sdk/current/core/android.jar": nil,
+ "prebuilts/sdk/current/public/android.jar": nil,
+ "prebuilts/sdk/current/public/framework.aidl": nil,
+ "prebuilts/sdk/current/public/core.jar": nil,
+ "prebuilts/sdk/current/system/android.jar": nil,
+ "prebuilts/sdk/current/test/android.jar": nil,
+ "prebuilts/sdk/28/public/api/sysprop-platform.txt": nil,
+ "prebuilts/sdk/28/system/api/sysprop-platform.txt": nil,
+ "prebuilts/sdk/28/test/api/sysprop-platform.txt": nil,
+ "prebuilts/sdk/28/public/api/sysprop-platform-removed.txt": nil,
+ "prebuilts/sdk/28/system/api/sysprop-platform-removed.txt": nil,
+ "prebuilts/sdk/28/test/api/sysprop-platform-removed.txt": nil,
+ "prebuilts/sdk/28/public/api/sysprop-platform-on-product.txt": nil,
+ "prebuilts/sdk/28/system/api/sysprop-platform-on-product.txt": nil,
+ "prebuilts/sdk/28/test/api/sysprop-platform-on-product.txt": nil,
+ "prebuilts/sdk/28/public/api/sysprop-platform-on-product-removed.txt": nil,
+ "prebuilts/sdk/28/system/api/sysprop-platform-on-product-removed.txt": nil,
+ "prebuilts/sdk/28/test/api/sysprop-platform-on-product-removed.txt": nil,
+ "prebuilts/sdk/28/public/api/sysprop-vendor.txt": nil,
+ "prebuilts/sdk/28/system/api/sysprop-vendor.txt": nil,
+ "prebuilts/sdk/28/test/api/sysprop-vendor.txt": nil,
+ "prebuilts/sdk/28/public/api/sysprop-vendor-removed.txt": nil,
+ "prebuilts/sdk/28/system/api/sysprop-vendor-removed.txt": nil,
+ "prebuilts/sdk/28/test/api/sysprop-vendor-removed.txt": nil,
+ "prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
+ "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["28", "current"],}`),
+
+ // For framework-res, which is an implicit dependency for framework
+ "AndroidManifest.xml": nil,
+ "build/target/product/security/testkey": nil,
+
+ "build/soong/scripts/jar-wrapper.sh": nil,
+
+ "build/make/core/proguard.flags": nil,
+ "build/make/core/proguard_basic_keeps.flags": nil,
+
+ "jdk8/jre/lib/jce.jar": nil,
+ "jdk8/jre/lib/rt.jar": nil,
+ "jdk8/lib/tools.jar": nil,
+
+ "bar-doc/a.java": nil,
+ "bar-doc/b.java": nil,
+ "bar-doc/IFoo.aidl": nil,
+ "bar-doc/known_oj_tags.txt": nil,
+ "external/doclava/templates-sdk": nil,
+
+ "cert/new_cert.x509.pem": nil,
+ "cert/new_cert.pk8": nil,
+
+ "android/sysprop/PlatformProperties.sysprop": nil,
+ "com/android/VendorProperties.sysprop": nil,
+ }
+
+ for k, v := range fs {
+ mockFS[k] = v
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ return ctx
+}
+
+func run(t *testing.T, ctx *android.TestContext, config android.Config) {
+ t.Helper()
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp", "prebuilts/sdk/Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+}
+
+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"
+ }
+ config := android.TestArchConfig(buildDir, env)
+ config.TestProductVariables.DeviceSystemSdkVersions = []string{"28"}
+ config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
+ return config
+
+}
+
+func test(t *testing.T, bp string) *android.TestContext {
+ t.Helper()
+ config := testConfig(nil)
+ ctx := testContext(config, bp, nil)
+ run(t, ctx, config)
+
+ return ctx
+}
+
+func TestSyspropLibrary(t *testing.T) {
+ ctx := test(t, `
+ sysprop_library {
+ name: "sysprop-platform",
+ srcs: ["android/sysprop/PlatformProperties.sysprop"],
+ api_packages: ["android.sysprop"],
+ property_owner: "Platform",
+ vendor_available: true,
+ }
+
+ sysprop_library {
+ name: "sysprop-platform-on-product",
+ srcs: ["android/sysprop/PlatformProperties.sysprop"],
+ api_packages: ["android.sysprop"],
+ property_owner: "Platform",
+ product_specific: true,
+ }
+
+ sysprop_library {
+ name: "sysprop-vendor",
+ srcs: ["com/android/VendorProperties.sysprop"],
+ api_packages: ["com.android"],
+ property_owner: "Vendor",
+ product_specific: true,
+ vendor_available: true,
+ }
+
+ java_library {
+ name: "java-platform",
+ srcs: ["c.java"],
+ sdk_version: "system_current",
+ libs: ["sysprop-platform"],
+ }
+
+ java_library {
+ name: "java-product",
+ srcs: ["c.java"],
+ sdk_version: "system_current",
+ product_specific: true,
+ libs: ["sysprop-platform", "sysprop-vendor"],
+ }
+
+ java_library {
+ name: "java-vendor",
+ srcs: ["c.java"],
+ sdk_version: "system_current",
+ soc_specific: true,
+ libs: ["sysprop-platform", "sysprop-vendor"],
+ }
+
+ cc_library {
+ name: "cc-client-platform",
+ srcs: ["d.cpp"],
+ static_libs: ["sysprop-platform"],
+ }
+
+ cc_library {
+ name: "cc-client-product",
+ srcs: ["d.cpp"],
+ product_specific: true,
+ static_libs: ["sysprop-platform-on-product", "sysprop-vendor"],
+ }
+
+ cc_library {
+ name: "cc-client-vendor",
+ srcs: ["d.cpp"],
+ soc_specific: true,
+ static_libs: ["sysprop-platform", "sysprop-vendor"],
+ }
+ `)
+
+ for _, variant := range []string{
+ "android_arm_armv7-a-neon_core_shared",
+ "android_arm_armv7-a-neon_core_static",
+ "android_arm_armv7-a-neon_vendor_shared",
+ "android_arm_armv7-a-neon_vendor_static",
+ "android_arm64_armv8-a_core_shared",
+ "android_arm64_armv8-a_core_static",
+ "android_arm64_armv8-a_vendor_shared",
+ "android_arm64_armv8-a_vendor_static",
+ } {
+ // Check for generated cc_library
+ ctx.ModuleForTests("libsysprop-platform", variant)
+ ctx.ModuleForTests("libsysprop-vendor", variant)
+ }
+
+ ctx.ModuleForTests("sysprop-platform", "android_common")
+ ctx.ModuleForTests("sysprop-vendor", "android_common")
+
+ // Check for exported includes
+ coreVariant := "android_arm64_armv8-a_core_static"
+ vendorVariant := "android_arm64_armv8-a_vendor_static"
+
+ platformInternalPath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/include"
+ platformSystemCorePath := "libsysprop-platform/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+ platformSystemVendorPath := "libsysprop-platform/android_arm64_armv8-a_vendor_static/gen/sysprop/system/include"
+
+ platformOnProductPath := "libsysprop-platform-on-product/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+
+ vendorInternalPath := "libsysprop-vendor/android_arm64_armv8-a_vendor_static/gen/sysprop/include"
+ vendorSystemPath := "libsysprop-vendor/android_arm64_armv8-a_core_static/gen/sysprop/system/include"
+
+ platformClient := ctx.ModuleForTests("cc-client-platform", coreVariant)
+ platformFlags := platformClient.Rule("cc").Args["cFlags"]
+
+ // Platform should use platform's internal header
+ if !strings.Contains(platformFlags, platformInternalPath) {
+ t.Errorf("flags for platform must contain %#v, but was %#v.",
+ platformInternalPath, platformFlags)
+ }
+
+ productClient := ctx.ModuleForTests("cc-client-product", coreVariant)
+ productFlags := productClient.Rule("cc").Args["cFlags"]
+
+ // Product should use platform's and vendor's system headers
+ if !strings.Contains(productFlags, platformOnProductPath) ||
+ !strings.Contains(productFlags, vendorSystemPath) {
+ t.Errorf("flags for product must contain %#v and %#v, but was %#v.",
+ platformSystemCorePath, vendorSystemPath, productFlags)
+ }
+
+ vendorClient := ctx.ModuleForTests("cc-client-vendor", vendorVariant)
+ vendorFlags := vendorClient.Rule("cc").Args["cFlags"]
+
+ // Vendor should use platform's system header and vendor's internal header
+ if !strings.Contains(vendorFlags, platformSystemVendorPath) ||
+ !strings.Contains(vendorFlags, vendorInternalPath) {
+ t.Errorf("flags for vendor must contain %#v and %#v, but was %#v.",
+ platformSystemVendorPath, vendorInternalPath, vendorFlags)
+ }
+}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index 1ab855d..d644f5f 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)
@@ -213,11 +214,13 @@
ctx.Fatalln("Error dumping make vars:", err)
}
+ env := config.Environment()
// Print the banner like make does
- ctx.Writer.Print(Banner(make_vars))
+ if !env.IsEnvTrue("ANDROID_QUIET_BUILD") {
+ ctx.Writer.Print(Banner(make_vars))
+ }
// Populate the environment
- env := config.Environment()
for _, name := range exportEnvVars {
if make_vars[name] == "" {
env.Unset(name)
diff --git a/ui/build/goma.go b/ui/build/goma.go
index 015a7c7..ff0b40e 100644
--- a/ui/build/goma.go
+++ b/ui/build/goma.go
@@ -73,7 +73,7 @@
cmd := Command(ctx, config, "goma_ctl.py ensure_start", gomaCtl, "ensure_start")
- if err := cmd.Run(); err != nil {
- ctx.Fatalf("goma_ctl.py ensure_start failed with: %v\n", err)
+ if output, err := cmd.CombinedOutput(); err != nil {
+ ctx.Fatalf("goma_ctl.py ensure_start failed with: %v\n%s\n", err, output)
}
}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index f924b9c..959d0bd 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -202,8 +202,11 @@
defer ctx.EndTrace()
runKati(ctx, config, katiCleanspecSuffix, []string{
+ "--werror_writable",
"--werror_implicit_rules",
"--werror_overriding_commands",
+ "--werror_real_to_phony",
+ "--werror_phony_looks_real",
"-f", "build/make/core/cleanbuild.mk",
"SOONG_MAKEVARS_MK=" + config.SoongMakeVarsMk(),
"TARGET_DEVICE_DIR=" + config.TargetDeviceDir(),
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 17decd0..b9713fe 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -74,7 +74,6 @@
}
var Configuration = map[string]PathConfig{
- "awk": Allowed,
"bash": Allowed,
"bc": Allowed,
"bzip2": Allowed,
@@ -127,6 +126,7 @@
"pkg-config": Forbidden,
// On Linux we'll use the toybox versions of these instead.
+ "awk": Toybox, // Strictly one-true-awk, but...
"basename": Toybox,
"cat": Toybox,
"chmod": Toybox,
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index c8eb382..2445c5b 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -27,6 +27,7 @@
format string
start time.Time
+ quiet bool
}
// NewStatusOutput returns a StatusOutput that represents the
@@ -35,12 +36,13 @@
//
// statusFormat takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported.
-func NewStatusOutput(w Writer, statusFormat string) status.StatusOutput {
+func NewStatusOutput(w Writer, statusFormat string, quietBuild bool) status.StatusOutput {
return &statusOutput{
writer: w,
format: statusFormat,
start: time.Now(),
+ quiet: quietBuild,
}
}
@@ -76,13 +78,12 @@
progress := s.progress(counts) + str
if result.Error != nil {
- hasCommand := ""
- if result.Command != "" {
- hasCommand = "\n"
+ targets := strings.Join(result.Outputs, " ")
+ if s.quiet || result.Command == "" {
+ s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s", targets, result.Output))
+ } else {
+ s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s\n%s", targets, result.Command, result.Output))
}
-
- s.writer.StatusAndMessage(progress, fmt.Sprintf("FAILED: %s\n%s%s%s",
- strings.Join(result.Outputs, " "), result.Command, hasCommand, result.Output))
} else if result.Output != "" {
s.writer.StatusAndMessage(progress, result.Output)
} else {