Merge "Add system_ext_specific"
diff --git a/Android.bp b/Android.bp
index 0ca11d3..f72d624 100644
--- a/Android.bp
+++ b/Android.bp
@@ -503,11 +503,15 @@
"soong-java",
],
srcs: [
+ "sdk/bp.go",
"sdk/sdk.go",
"sdk/update.go",
],
testSrcs: [
+ "sdk/cc_sdk_test.go",
+ "sdk/java_sdk_test.go",
"sdk/sdk_test.go",
+ "sdk/testing.go",
],
pluginFor: ["soong_build"],
}
diff --git a/README.md b/README.md
index 37feb1d..b6fda50 100644
--- a/README.md
+++ b/README.md
@@ -74,7 +74,7 @@
```
Variables are scoped to the remainder of the file they are declared in, as well
-as any child blueprint files. Variables are immutable with one exception - they
+as any child Android.bp files. Variables are immutable with one exception - they
can be appended to with a += assignment, but only before they have been
referenced.
@@ -168,37 +168,114 @@
}
```
-### Name resolution
+### Referencing Modules
-Soong provides the ability for modules in different directories to specify
-the same name, as long as each module is declared within a separate namespace.
-A namespace can be declared like this:
+A module `libfoo` can be referenced by its name
```
-soong_namespace {
- imports: ["path/to/otherNamespace1", "path/to/otherNamespace2"],
+cc_binary {
+ name: "app",
+ shared_libs: ["libfoo"],
}
```
-Each Soong module is assigned a namespace based on its location in the tree.
-Each Soong module is considered to be in the namespace defined by the
-soong_namespace found in an Android.bp in the current directory or closest
-ancestor directory, unless no such soong_namespace module is found, in which
-case the module is considered to be in the implicit root namespace.
+Obviously, this works only if there is only one `libfoo` module in the source
+tree. Ensuring such name uniqueness for larger trees may become problematic. We
+might also want to use the same name in multiple mutually exclusive subtrees
+(for example, implementing different devices) deliberately in order to describe
+a functionally equivalent module. Enter Soong namespaces.
-When Soong attempts to resolve dependency D declared my module M in namespace
-N which imports namespaces I1, I2, I3..., then if D is a fully-qualified name
-of the form "//namespace:module", only the specified namespace will be searched
-for the specified module name. Otherwise, Soong will first look for a module
-named D declared in namespace N. If that module does not exist, Soong will look
-for a module named D in namespaces I1, I2, I3... Lastly, Soong will look in the
-root namespace.
+#### Namespaces
-Until we have fully converted from Make to Soong, it will be necessary for the
-Make product config to specify a value of PRODUCT_SOONG_NAMESPACES. Its value
-should be a space-separated list of namespaces that Soong export to Make to be
-built by the `m` command. After we have fully converted from Make to Soong, the
-details of enabling namespaces could potentially change.
+A presense of the `soong_namespace {..}` in an Android.bp file defines a
+**namespace**. For instance, having
+
+```
+soong_namespace {
+ ...
+}
+...
+```
+
+in `device/google/bonito/Android.bp` informs Soong that within the
+`device/google/bonito` package the module names are unique, that is, all the
+modules defined in the Android.bp files in the `device/google/bonito/` tree have
+unique names. However, there may be modules with the same names outside
+`device/google/bonito` tree. Indeed, there is a module `"pixelstats-vendor"`
+both in `device/google/bonito/pixelstats` and in
+`device/google/coral/pixelstats`.
+
+The name of a namespace is the path of its directory. The name of the namespace
+in the example above is thus `device/google/bonito`.
+
+An implicit **global namespace** corresponds to the source tree as a whole. It
+has empty name.
+
+A module name's **scope** is the smallest namespace containing it. Suppose a
+source tree has `device/my` and `device/my/display` namespaces. If `libfoo`
+module is defined in `device/co/display/lib/Android.bp`, its namespace is
+`device/co/display`.
+
+The name uniqueness thus means that module's name is unique within its scope. In
+other words, "//_scope_:_name_" is globally unique module reference, e.g,
+`"//device/google/bonito:pixelstats-vendor"`. _Note_ that the name of the
+namespace for a module may be different from module's package name: `libfoo`
+belongs to `device/my/display` namespace but is contained in
+`device/my/display/lib` package.
+
+#### Name Resolution
+
+The form of a module reference determines how Soong locates the module.
+
+For a **global reference** of the "//_scope_:_name_" form, Soong verifies there
+is a namespace called "_scope_", then verifies it contains a "_name_" module and
+uses it. Soong verifies there is only one "_name_" in "_scope_" at the beginning
+when it parses Android.bp files.
+
+A **local reference** has "_name_" form, and resolving it involves looking for a
+module "_name_" in one or more namespaces. By default only the global namespace
+is searched for "_name_" (in other words, only the modules not belonging to an
+explicitly defined scope are considered). The `imports` attribute of the
+`soong_namespaces` allows to specify where to look for modules . For instance,
+with `device/google/bonito/Android.bp` containing
+
+```
+soong_namespace {
+ imports: [
+ "hardware/google/interfaces",
+ "hardware/google/pixel",
+ "hardware/qcom/bootctrl",
+ ],
+}
+```
+
+a reference to `"libpixelstats"` will resolve to the module defined in
+`hardware/google/pixel/pixelstats/Android.bp` because this module is in
+`hardware/google/pixel` namespace.
+
+**TODO**: Conventionally, languages with similar concepts provide separate
+constructs for namespace definition and name resolution (`namespace` and `using`
+in C++, for instance). Should Soong do that, too?
+
+#### Referencing modules in makefiles
+
+While we are gradually converting makefiles to Android.bp files, Android build
+is described by a mixture of Android.bp and Android.mk files, and a module
+defined in an Android.mk file can reference a module defined in Android.bp file.
+For instance, a binary still defined in an Android.mk file may have a library
+defined in already converted Android.bp as a dependency.
+
+A module defined in an Android.bp file and belonging to the global namespace can
+be referenced from a makefile without additional effort. If a module belongs to
+an explicit namespace, it can be referenced from a makefile only after after the
+name of the namespace has been added to the value of PRODUCT_SOONG_NAMESPACES
+variable.
+
+Note that makefiles have no notion of namespaces and exposing namespaces with
+the same modules via PRODUCT_SOONG_NAMESPACES may cause Make failure. For
+instance, exposing both `device/google/bonito` and `device/google/coral`
+namespaces will cause Make failure because it will see two targets for the
+`pixelstats-vendor` module.
### Visibility
@@ -266,7 +343,7 @@
### Formatter
-Soong includes a canonical formatter for blueprint files, similar to
+Soong includes a canonical formatter for Android.bp files, similar to
[gofmt](https://golang.org/cmd/gofmt/). To recursively reformat all Android.bp files
in the current directory:
```
diff --git a/android/config.go b/android/config.go
index 1e5a24d..271a54a 100644
--- a/android/config.go
+++ b/android/config.go
@@ -418,6 +418,18 @@
return PathForOutput(ctx, "host", c.PrebuiltOS(), "bin", tool)
}
+func (c *config) HostJNIToolPath(ctx PathContext, path string) Path {
+ ext := ".so"
+ if runtime.GOOS == "darwin" {
+ ext = ".dylib"
+ }
+ return PathForOutput(ctx, "host", c.PrebuiltOS(), "lib64", path+ext)
+}
+
+func (c *config) HostJavaToolPath(ctx PathContext, path string) Path {
+ return PathForOutput(ctx, "host", c.PrebuiltOS(), "framework", path)
+}
+
// HostSystemTool looks for non-hermetic tools from the system we're running on.
// Generally shouldn't be used, but useful to find the XCode SDK, etc.
func (c *config) HostSystemTool(name string) string {
diff --git a/android/defaults.go b/android/defaults.go
index f489c02..7597446 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -151,7 +151,8 @@
module.AddProperties(
&hostAndDeviceProperties{},
commonProperties,
- &variableProperties{})
+ &variableProperties{},
+ &ApexProperties{})
InitArchModule(module)
InitDefaultableModule(module)
diff --git a/android/image.go b/android/image.go
index 5ec1b16..8424cf8 100644
--- a/android/image.go
+++ b/android/image.go
@@ -14,7 +14,7 @@
package android
-// ImageInterface is implemented by modules that need to be split by the ImageMutator.
+// ImageInterface is implemented by modules that need to be split by the imageMutator.
type ImageInterface interface {
// ImageMutatorBegin is called before any other method in the ImageInterface.
ImageMutatorBegin(ctx BaseModuleContext)
@@ -48,9 +48,9 @@
RecoveryVariation string = "recovery"
)
-// ImageMutator creates variants for modules that implement the ImageInterface that
+// imageMutator creates variants for modules that implement the ImageInterface that
// allow them to build differently for each partition (recovery, core, vendor, etc.).
-func ImageMutator(ctx BottomUpMutatorContext) {
+func imageMutator(ctx BottomUpMutatorContext) {
if ctx.Os() != Android {
return
}
diff --git a/android/module.go b/android/module.go
index 2ae2961..b4f8f1a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -778,6 +778,13 @@
*m.hostAndDeviceProperties.Device_supported)
}
+func (m *ModuleBase) HostSupported() bool {
+ return m.commonProperties.HostOrDeviceSupported == HostSupported ||
+ m.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported &&
+ (m.hostAndDeviceProperties.Host_supported != nil &&
+ *m.hostAndDeviceProperties.Host_supported)
+}
+
func (m *ModuleBase) Platform() bool {
return !m.DeviceSpecific() && !m.SocSpecific() && !m.ProductSpecific() && !m.SystemExtSpecific()
}
diff --git a/android/mutator.go b/android/mutator.go
index 0d253eb..e9ccd7f 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -78,17 +78,18 @@
registerLoadHookMutator,
RegisterNamespaceMutator,
// Rename package module types.
- registerPackageRenamer,
+ RegisterPackageRenamer,
RegisterPrebuiltsPreArchMutators,
- registerVisibilityRuleChecker,
+ RegisterVisibilityRuleChecker,
RegisterDefaultsPreArchMutators,
- registerVisibilityRuleGatherer,
+ RegisterVisibilityRuleGatherer,
}
func registerArchMutator(ctx RegisterMutatorsContext) {
ctx.BottomUp("os", osMutator).Parallel()
ctx.BottomUp("arch", archMutator).Parallel()
ctx.TopDown("arch_hooks", archHookMutator).Parallel()
+ ctx.BottomUp("image", imageMutator).Parallel()
}
var preDeps = []RegisterMutatorFunc{
@@ -98,7 +99,7 @@
var postDeps = []RegisterMutatorFunc{
registerPathDepsMutator,
RegisterPrebuiltsPostDepsMutators,
- registerVisibilityRuleEnforcer,
+ RegisterVisibilityRuleEnforcer,
registerNeverallowMutator,
RegisterOverridePostDepsMutators,
}
diff --git a/android/override_module.go b/android/override_module.go
index f946587..45f7be0 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -82,13 +82,16 @@
// Interface for overridable module types, e.g. android_app, apex
type OverridableModule interface {
+ Module
+ moduleBase() *OverridableModuleBase
+
setOverridableProperties(prop []interface{})
addOverride(o OverrideModule)
getOverrides() []OverrideModule
override(ctx BaseModuleContext, o OverrideModule)
- getOverriddenBy() string
+ GetOverriddenBy() string
setOverridesProperty(overridesProperties *[]string)
@@ -97,6 +100,10 @@
OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext)
}
+type overridableModuleProperties struct {
+ OverriddenBy string `blueprint:"mutated"`
+}
+
// Base module struct for overridable module types
type OverridableModuleBase struct {
// List of OverrideModules that override this base module
@@ -114,12 +121,17 @@
// override information is propagated and aggregated correctly.
overridesProperty *[]string
- overriddenBy string
+ properties overridableModuleProperties
}
func InitOverridableModule(m OverridableModule, overridesProperty *[]string) {
m.setOverridableProperties(m.(Module).GetProperties())
m.setOverridesProperty(overridesProperty)
+ m.AddProperties(&m.moduleBase().properties)
+}
+
+func (o *OverridableModuleBase) moduleBase() *OverridableModuleBase {
+ return o
}
func (b *OverridableModuleBase) setOverridableProperties(prop []interface{}) {
@@ -162,11 +174,15 @@
}
}
}
- b.overriddenBy = o.Name()
+ b.properties.OverriddenBy = o.Name()
}
-func (b *OverridableModuleBase) getOverriddenBy() string {
- return b.overriddenBy
+// GetOverriddenBy returns the name of the override module that has overridden this module.
+// For example, if an override module foo has its 'base' property set to bar, then another local variant
+// of bar is created and its properties are overriden by foo. This method returns bar when called from
+// the new local variant. It returns "" when called from the original variant of bar.
+func (b *OverridableModuleBase) GetOverriddenBy() string {
+ return b.properties.OverriddenBy
}
func (b *OverridableModuleBase) OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) {
@@ -247,7 +263,7 @@
func replaceDepsOnOverridingModuleMutator(ctx BottomUpMutatorContext) {
if b, ok := ctx.Module().(OverridableModule); ok {
- if o := b.getOverriddenBy(); o != "" {
+ if o := b.GetOverriddenBy(); o != "" {
// Redirect dependencies on the overriding module to this overridden module. Overriding
// modules are basically pseudo modules, and all build actions are associated to overridden
// modules. Therefore, dependencies on overriding modules need to be forwarded there as well.
diff --git a/android/package.go b/android/package.go
index 880d6a9..ed604c6 100644
--- a/android/package.go
+++ b/android/package.go
@@ -98,7 +98,7 @@
}
// Registers the function that renames the packages.
-func registerPackageRenamer(ctx RegisterMutatorsContext) {
+func RegisterPackageRenamer(ctx RegisterMutatorsContext) {
ctx.BottomUp("packageRenamer", packageRenamer).Parallel()
ctx.BottomUp("packageErrorReporter", packageErrorReporter).Parallel()
}
diff --git a/android/package_ctx.go b/android/package_ctx.go
index cf8face..d3527fa 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -16,7 +16,6 @@
import (
"fmt"
- "runtime"
"strings"
"github.com/google/blueprint"
@@ -177,46 +176,30 @@
// package-scoped variable's initialization.
func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
return p.VariableFunc(name, func(ctx PackageVarContext) string {
- return p.HostBinToolPath(ctx, path).String()
+ return ctx.Config().HostToolPath(ctx, path).String()
})
}
-func (p PackageContext) HostBinToolPath(ctx PackageVarContext, path string) Path {
- return PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "bin", path)
-}
-
// HostJNIToolVariable returns a Variable whose value is the path to a host tool
// in the lib directory for host targets. It may only be called during a Go
// package's initialization - either from the init() function or as part of a
// package-scoped variable's initialization.
func (p PackageContext) HostJNIToolVariable(name, path string) blueprint.Variable {
return p.VariableFunc(name, func(ctx PackageVarContext) string {
- return p.HostJNIToolPath(ctx, path).String()
+ return ctx.Config().HostJNIToolPath(ctx, path).String()
})
}
-func (p PackageContext) HostJNIToolPath(ctx PackageVarContext, path string) Path {
- ext := ".so"
- if runtime.GOOS == "darwin" {
- ext = ".dylib"
- }
- return PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "lib64", path+ext)
-}
-
// HostJavaToolVariable returns a Variable whose value is the path to a host
// tool in the frameworks directory for host targets. It may only be called
// during a Go package's initialization - either from the init() function or as
// part of a package-scoped variable's initialization.
func (p PackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
return p.VariableFunc(name, func(ctx PackageVarContext) string {
- return p.HostJavaToolPath(ctx, path).String()
+ return ctx.Config().HostJavaToolPath(ctx, path).String()
})
}
-func (p PackageContext) HostJavaToolPath(ctx PackageVarContext, path string) Path {
- return PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", path)
-}
-
// IntermediatesPathVariable returns a Variable whose value is the intermediate
// directory appended with the supplied path. It may only be called during a Go
// package's initialization - either from the init() function or as part of a
diff --git a/android/package_test.go b/android/package_test.go
index ae286d6..8071c51 100644
--- a/android/package_test.go
+++ b/android/package_test.go
@@ -88,7 +88,7 @@
ctx := NewTestArchContext()
ctx.RegisterModuleType("package", PackageFactory)
- ctx.PreArchMutators(registerPackageRenamer)
+ ctx.PreArchMutators(RegisterPackageRenamer)
ctx.Register()
ctx.MockFileSystem(fs)
diff --git a/android/paths.go b/android/paths.go
index 8dbb086..1a37a34 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -247,6 +247,33 @@
return ret
}
+// OutputPaths is a slice of OutputPath objects, with helpers to operate on the collection.
+type OutputPaths []OutputPath
+
+// Paths returns the OutputPaths as a Paths
+func (p OutputPaths) Paths() Paths {
+ if p == nil {
+ return nil
+ }
+ ret := make(Paths, len(p))
+ for i, path := range p {
+ ret[i] = path
+ }
+ return ret
+}
+
+// Strings returns the string forms of the writable paths.
+func (p OutputPaths) Strings() []string {
+ if p == nil {
+ return nil
+ }
+ ret := make([]string, len(p))
+ for i, path := range p {
+ ret[i] = path.String()
+ }
+ return ret
+}
+
// PathsAndMissingDepsForModuleSrcExcludes returns Paths rooted from the module's local source directory, excluding
// paths listed in the excludes arguments, and a list of missing dependencies. It expands globs, references to
// SourceFileProducer modules using the ":name" syntax, and references to OutputFileProducer modules using the
diff --git a/android/prebuilt_etc_test.go b/android/prebuilt_etc_test.go
index 3855dac..2c4123f 100644
--- a/android/prebuilt_etc_test.go
+++ b/android/prebuilt_etc_test.go
@@ -29,9 +29,6 @@
ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
- ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) {
- ctx.BottomUp("prebuilt_etc", ImageMutator).Parallel()
- })
ctx.Register()
mockFiles := map[string][]byte{
"Android.bp": []byte(bp),
diff --git a/android/sdk.go b/android/sdk.go
index 73cb256..533bd0e 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -17,6 +17,7 @@
import (
"strings"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -31,9 +32,6 @@
MemberName() string
BuildWithSdks(sdks SdkRefs)
RequiredSdks() SdkRefs
-
- // Build a snapshot of the module.
- BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder)
}
// SdkRef refers to a version of an SDK
@@ -167,16 +165,92 @@
// Unzip the supplied zip into the snapshot relative directory destDir.
UnzipToSnapshot(zipPath Path, destDir string)
- // Get the AndroidBpFile for the snapshot.
- AndroidBpFile() GeneratedSnapshotFile
-
- // Get a versioned name appropriate for the SDK snapshot version being taken.
- VersionedSdkMemberName(unversionedName string) interface{}
+ // Add a new prebuilt module to the snapshot. The returned module
+ // must be populated with the module type specific properties. The following
+ // properties will be automatically populated.
+ //
+ // * name
+ // * sdk_member_name
+ // * prefer
+ //
+ // This will result in two Soong modules being generated in the Android. One
+ // that is versioned, coupled to the snapshot version and marked as
+ // prefer=true. And one that is not versioned, not marked as prefer=true and
+ // will only be used if the equivalently named non-prebuilt module is not
+ // present.
+ AddPrebuiltModule(member SdkMember, moduleType string) BpModule
}
-// Provides support for generating a file, e.g. the Android.bp file.
-type GeneratedSnapshotFile interface {
- Printfln(format string, args ...interface{})
- Indent()
- Dedent()
+// A set of properties for use in a .bp file.
+type BpPropertySet interface {
+ // Add a property, the value can be one of the following types:
+ // * string
+ // * array of the above
+ // * bool
+ // * BpPropertySet
+ //
+ // It is an error is multiples properties with the same name are added.
+ AddProperty(name string, value interface{})
+
+ // Add a property set with the specified name and return so that additional
+ // properties can be added.
+ AddPropertySet(name string) BpPropertySet
+}
+
+// A .bp module definition.
+type BpModule interface {
+ BpPropertySet
+}
+
+// An individual member of the SDK, includes all of the variants that the SDK
+// requires.
+type SdkMember interface {
+ // The name of the member.
+ Name() string
+
+ // All the variants required by the SDK.
+ Variants() []SdkAware
+}
+
+// Interface that must be implemented for every type that can be a member of an
+// sdk.
+//
+// The basic implementation should look something like this, where ModuleType is
+// the name of the module type being supported.
+//
+// var ModuleTypeSdkMemberType = newModuleTypeSdkMemberType()
+//
+// func newModuleTypeSdkMemberType() android.SdkMemberType {
+// return &moduleTypeSdkMemberType{}
+// }
+//
+// type moduleTypeSdkMemberType struct {
+// }
+//
+// ...methods...
+//
+type SdkMemberType interface {
+ // Add dependencies from the SDK module to all the variants the member
+ // contributes to the SDK. The exact set of variants required is determined
+ // by the SDK and its properties. The dependencies must be added with the
+ // supplied tag.
+ //
+ // The BottomUpMutatorContext provided is for the SDK module.
+ AddDependencies(mctx BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string)
+
+ // Return true if the supplied module is an instance of this member type.
+ //
+ // This is used to check the type of each variant before added to the
+ // SdkMember. Returning false will cause an error to be logged expaining that
+ // the module is not allowed in whichever sdk property it was added.
+ IsInstance(module Module) bool
+
+ // Build the snapshot for the SDK member
+ //
+ // The ModuleContext provided is for the SDK module, so information for
+ // variants in the supplied member can be accessed using the Other... methods.
+ //
+ // The SdkMember is guaranteed to contain variants for which the
+ // IsInstance(Module) method returned true.
+ BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember)
}
diff --git a/android/visibility.go b/android/visibility.go
index a7e718b..c28ec93 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -117,12 +117,15 @@
}
func (c compositeRule) String() string {
+ return "[" + strings.Join(c.Strings(), ", ") + "]"
+}
+
+func (c compositeRule) Strings() []string {
s := make([]string, 0, len(c))
for _, r := range c {
s = append(s, r.String())
}
-
- return "[" + strings.Join(s, ", ") + "]"
+ return s
}
// A packageRule is a visibility rule that matches modules in a specific package (i.e. directory).
@@ -189,7 +192,7 @@
// The rule checker needs to be registered before defaults expansion to correctly check that
// //visibility:xxx isn't combined with other packages in the same list in any one module.
-func registerVisibilityRuleChecker(ctx RegisterMutatorsContext) {
+func RegisterVisibilityRuleChecker(ctx RegisterMutatorsContext) {
ctx.BottomUp("visibilityRuleChecker", visibilityRuleChecker).Parallel()
}
@@ -199,12 +202,12 @@
// having to process multiple variants for each module. This goes after defaults expansion to gather
// the complete visibility lists from flat lists and after the package info is gathered to ensure
// that default_visibility is available.
-func registerVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
+func RegisterVisibilityRuleGatherer(ctx RegisterMutatorsContext) {
ctx.BottomUp("visibilityRuleGatherer", visibilityRuleGatherer).Parallel()
}
// This must be registered after the deps have been resolved.
-func registerVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
+func RegisterVisibilityRuleEnforcer(ctx RegisterMutatorsContext) {
ctx.TopDown("visibilityRuleEnforcer", visibilityRuleEnforcer).Parallel()
}
@@ -384,8 +387,6 @@
qualified := createQualifiedModuleName(ctx)
- moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
-
// Visit all the dependencies making sure that this module has access to them all.
ctx.VisitDirectDeps(func(dep Module) {
depName := ctx.OtherModuleName(dep)
@@ -397,19 +398,25 @@
return
}
- value, ok := moduleToVisibilityRule.Load(depQualified)
- var rule compositeRule
- if ok {
- rule = value.(compositeRule)
- } else {
- rule = packageDefaultVisibility(ctx, depQualified)
- }
+ rule := effectiveVisibilityRules(ctx, depQualified)
if rule != nil && !rule.matches(qualified) {
ctx.ModuleErrorf("depends on %s which is not visible to this module", depQualified)
}
})
}
+func effectiveVisibilityRules(ctx BaseModuleContext, qualified qualifiedModuleName) compositeRule {
+ moduleToVisibilityRule := moduleToVisibilityRuleMap(ctx)
+ value, ok := moduleToVisibilityRule.Load(qualified)
+ var rule compositeRule
+ if ok {
+ rule = value.(compositeRule)
+ } else {
+ rule = packageDefaultVisibility(ctx, qualified)
+ }
+ return rule
+}
+
func createQualifiedModuleName(ctx BaseModuleContext) qualifiedModuleName {
moduleName := ctx.ModuleName()
dir := ctx.ModuleDir()
@@ -433,3 +440,19 @@
packageQualifiedId = packageQualifiedId.getContainingPackageId()
}
}
+
+// Get the effective visibility rules, i.e. the actual rules that affect the visibility of the
+// property irrespective of where they are defined.
+//
+// Includes visibility rules specified by package default_visibility and/or on defaults.
+// Short hand forms, e.g. //:__subpackages__ are replaced with their full form, e.g.
+// //package/containing/rule:__subpackages__.
+func EffectiveVisibilityRules(ctx BaseModuleContext, module Module) []string {
+ moduleName := ctx.OtherModuleName(module)
+ dir := ctx.OtherModuleDir(module)
+ qualified := qualifiedModuleName{dir, moduleName}
+
+ rule := effectiveVisibilityRules(ctx, qualified)
+
+ return rule.Strings()
+}
diff --git a/android/visibility_test.go b/android/visibility_test.go
index fd9e98c..1984a21 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -874,11 +874,11 @@
ctx.RegisterModuleType("package", PackageFactory)
ctx.RegisterModuleType("mock_library", newMockLibraryModule)
ctx.RegisterModuleType("mock_defaults", defaultsFactory)
- ctx.PreArchMutators(registerPackageRenamer)
- ctx.PreArchMutators(registerVisibilityRuleChecker)
+ ctx.PreArchMutators(RegisterPackageRenamer)
+ ctx.PreArchMutators(RegisterVisibilityRuleChecker)
ctx.PreArchMutators(RegisterDefaultsPreArchMutators)
- ctx.PreArchMutators(registerVisibilityRuleGatherer)
- ctx.PostDepsMutators(registerVisibilityRuleEnforcer)
+ ctx.PreArchMutators(RegisterVisibilityRuleGatherer)
+ ctx.PostDepsMutators(RegisterVisibilityRuleEnforcer)
ctx.Register()
ctx.MockFileSystem(fs)
diff --git a/apex/androidmk.go b/apex/androidmk.go
index dd5da97..35622f0 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -168,7 +168,6 @@
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " "))
}
fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)")
- fmt.Fprintln(w, "$(LOCAL_INSTALLED_MODULE): .KATI_IMPLICIT_OUTPUTS :=", a.outputFile.String())
} else {
fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
diff --git a/apex/apex.go b/apex/apex.go
index 289175b..3dde149 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1157,12 +1157,12 @@
})
// check apex_available requirements
- if !ctx.Host() {
+ if !ctx.Host() && !a.testApex {
for _, fi := range filesInfo {
if am, ok := fi.module.(android.ApexModule); ok {
if !am.AvailableFor(ctx.ModuleName()) {
ctx.ModuleErrorf("requires %q that is not available for the APEX", fi.module.Name())
- return
+ // don't stop so that we can report other violations in the same run
}
}
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 509d760..944852d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -140,7 +140,6 @@
ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
})
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("image", android.ImageMutator).Parallel()
ctx.BottomUp("link", cc.LinkageMutator).Parallel()
ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
@@ -2977,6 +2976,15 @@
}
`)
+ originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(android.OverridableModule)
+ overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image").Module().(android.OverridableModule)
+ if originalVariant.GetOverriddenBy() != "" {
+ t.Errorf("GetOverriddenBy should be empty, but was %q", originalVariant.GetOverriddenBy())
+ }
+ if overriddenVariant.GetOverriddenBy() != "override_myapex" {
+ t.Errorf("GetOverriddenBy should be \"override_myapex\", but was %q", overriddenVariant.GetOverriddenBy())
+ }
+
module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex_image")
apexRule := module.Rule("apexRule")
copyCmds := apexRule.Args["copy_commands"]
diff --git a/apex/builder.go b/apex/builder.go
index f199bd4..7fe0af3 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -43,7 +43,7 @@
if !ctx.Config().FrameworksBaseDirExists(ctx) {
return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool)
} else {
- return pctx.HostBinToolPath(ctx, tool).String()
+ return ctx.Config().HostToolPath(ctx, tool).String()
}
})
}
@@ -476,7 +476,7 @@
apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
a.outputFile = android.PathForModuleInstall(&factx, "apex", apexName)
- if a.installable() {
+ if a.installable() && a.GetOverriddenBy() == "" {
installPath := android.PathForModuleInstall(ctx, "apex", apexName)
devicePath := android.InstallPathToOnDevicePath(ctx, installPath)
addFlattenedFileContextsInfos(ctx, apexName+":"+devicePath+":"+a.fileContexts.String())
diff --git a/cc/cc.go b/cc/cc.go
index f306a00..a56978d 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -37,7 +37,6 @@
android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("vndk", VndkMutator).Parallel()
- ctx.BottomUp("image", android.ImageMutator).Parallel()
ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
ctx.BottomUp("test_per_src", TestPerSrcMutator).Parallel()
@@ -95,6 +94,7 @@
GeneratedSources []string
GeneratedHeaders []string
+ GeneratedDeps []string
ReexportGeneratedHeaders []string
@@ -121,14 +121,16 @@
// Paths to generated source files
GeneratedSources android.Paths
GeneratedHeaders android.Paths
+ GeneratedDeps android.Paths
- Flags []string
- IncludeDirs android.Paths
- SystemIncludeDirs android.Paths
- ReexportedDirs android.Paths
- ReexportedSystemDirs android.Paths
- ReexportedFlags []string
- ReexportedDeps android.Paths
+ Flags []string
+ IncludeDirs android.Paths
+ SystemIncludeDirs android.Paths
+ ReexportedDirs android.Paths
+ ReexportedSystemDirs android.Paths
+ ReexportedFlags []string
+ ReexportedGeneratedHeaders android.Paths
+ ReexportedDeps android.Paths
// Paths to crt*.o files
CrtBegin, CrtEnd android.OptionalPath
@@ -218,7 +220,7 @@
// Make this module available when building for recovery
Recovery_available *bool
- // Set by ImageMutator
+ // Set by imageMutator
CoreVariantNeeded bool `blueprint:"mutated"`
RecoveryVariantNeeded bool `blueprint:"mutated"`
VendorVariants []string `blueprint:"mutated"`
@@ -895,6 +897,13 @@
return nil
}
+func (c *Module) ExportedGeneratedHeaders() android.Paths {
+ if flagsProducer, ok := c.linker.(exportedFlagsProducer); ok {
+ return flagsProducer.exportedGeneratedHeaders()
+ }
+ return nil
+}
+
func isBionic(name string) bool {
switch name {
case "libc", "libm", "libdl", "libdl_android", "linker":
@@ -1906,6 +1915,7 @@
depPaths.ReexportedSystemDirs = append(depPaths.ReexportedSystemDirs, exporter.exportedSystemDirs()...)
depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, exporter.exportedFlags()...)
depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, exporter.exportedDeps()...)
+ depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.exportedGeneratedHeaders()...)
}
ctx.VisitDirectDeps(func(dep android.Module) {
@@ -1929,11 +1939,15 @@
case genHeaderDepTag, genHeaderExportDepTag:
if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders,
+ genRule.GeneratedSourceFiles()...)
+ depPaths.GeneratedDeps = append(depPaths.GeneratedDeps,
genRule.GeneratedDeps()...)
dirs := genRule.GeneratedHeaderDirs()
depPaths.IncludeDirs = append(depPaths.IncludeDirs, dirs...)
if depTag == genHeaderExportDepTag {
depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, dirs...)
+ depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders,
+ genRule.GeneratedSourceFiles()...)
depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, genRule.GeneratedDeps()...)
// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
c.sabi.Properties.ReexportedIncludes = append(c.sabi.Properties.ReexportedIncludes, dirs.Strings()...)
@@ -2046,7 +2060,8 @@
if _, ok := ccDep.(*Module); ok {
if i, ok := ccDep.(*Module).linker.(exportedFlagsProducer); ok {
depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, i.exportedSystemDirs()...)
- depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, i.exportedDeps()...)
+ depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, i.exportedGeneratedHeaders()...)
+ depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, i.exportedDeps()...)
depPaths.Flags = append(depPaths.Flags, i.exportedFlags()...)
if t.ReexportFlags {
@@ -2244,10 +2259,12 @@
depPaths.IncludeDirs = android.FirstUniquePaths(depPaths.IncludeDirs)
depPaths.SystemIncludeDirs = android.FirstUniquePaths(depPaths.SystemIncludeDirs)
depPaths.GeneratedHeaders = android.FirstUniquePaths(depPaths.GeneratedHeaders)
+ depPaths.GeneratedDeps = android.FirstUniquePaths(depPaths.GeneratedDeps)
depPaths.ReexportedDirs = android.FirstUniquePaths(depPaths.ReexportedDirs)
depPaths.ReexportedSystemDirs = android.FirstUniquePaths(depPaths.ReexportedSystemDirs)
depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags)
depPaths.ReexportedDeps = android.FirstUniquePaths(depPaths.ReexportedDeps)
+ depPaths.ReexportedGeneratedHeaders = android.FirstUniquePaths(depPaths.ReexportedGeneratedHeaders)
if c.sabi != nil {
c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)
@@ -2459,7 +2476,6 @@
&PgoProperties{},
&XomProperties{},
&android.ProtoProperties{},
- &android.ApexProperties{},
)
android.InitDefaultsModule(module)
diff --git a/cc/compiler.go b/cc/compiler.go
index 671861b..1ced451 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -27,6 +27,10 @@
"android/soong/cc/config"
)
+var (
+ allowedManualInterfacePaths = []string{"vendor/", "hardware/"}
+)
+
// This file contains the basic C/C++/assembly to .o compliation steps
type BaseCompilerProperties struct {
@@ -509,6 +513,12 @@
flags.Local.CFlags = append(flags.Local.CFlags, "-fopenmp")
}
+ // Exclude directories from manual binder interface whitelisting.
+ //TODO(b/145621474): Move this check into IInterface.h when clang-tidy no longer uses absolute paths.
+ if android.PrefixInList(ctx.ModuleDir(), allowedManualInterfacePaths) {
+ flags.Local.CFlags = append(flags.Local.CFlags, "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES")
+ }
+
return flags
}
@@ -550,7 +560,7 @@
}
func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
- pathDeps := deps.GeneratedHeaders
+ pathDeps := deps.GeneratedDeps
pathDeps = append(pathDeps, ndkPathDeps(ctx)...)
buildFlags := flagsToBuilderFlags(flags)
diff --git a/cc/config/global.go b/cc/config/global.go
index 0943126..0a09fa4 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -48,6 +48,8 @@
"-fno-strict-aliasing",
"-Werror=date-time",
+ "-Werror=pragma-pack",
+ "-Werror=pragma-pack-suspicious-include",
}
commonGlobalConlyflags = []string{}
diff --git a/cc/fuzz.go b/cc/fuzz.go
index bb89bb4..c2b0ff4 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -345,6 +345,11 @@
return
}
+ // Discard modules that are in an unavailable namespace.
+ if !ccModule.ExportedToMake() {
+ return
+ }
+
s.fuzzTargets[module.Name()] = true
hostOrTargetString := "target"
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
index 785e3e1..9f159e5 100644
--- a/cc/genrule_test.go
+++ b/cc/genrule_test.go
@@ -74,13 +74,13 @@
t.Fatal(errs)
}
- gen := ctx.ModuleForTests("gen", "android_arm_armv7-a-neon").Output("out_arm")
+ gen := ctx.ModuleForTests("gen", "android_arm_armv7-a-neon_core").Output("out_arm")
expected := []string{"foo"}
if !reflect.DeepEqual(expected, gen.Inputs.Strings()) {
t.Errorf(`want arm inputs %v, got %v`, expected, gen.Inputs.Strings())
}
- gen = ctx.ModuleForTests("gen", "android_arm64_armv8-a").Output("out_arm64")
+ gen = ctx.ModuleForTests("gen", "android_arm64_armv8-a_core").Output("out_arm64")
expected = []string{"bar"}
if !reflect.DeepEqual(expected, gen.Inputs.Strings()) {
t.Errorf(`want arm64 inputs %v, got %v`, expected, gen.Inputs.Strings())
diff --git a/cc/library.go b/cc/library.go
index 98cae3d..4b8e052 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -24,6 +24,7 @@
"strings"
"sync"
+ "github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
"android/soong/android"
@@ -237,6 +238,7 @@
systemDirs android.Paths
flags []string
deps android.Paths
+ headers android.Paths
}
func (f *flagExporter) exportedIncludes(ctx ModuleContext) android.Paths {
@@ -280,6 +282,12 @@
f.deps = append(f.deps, deps...)
}
+// addExportedGeneratedHeaders does nothing but collects generated header files.
+// This can be differ to exportedDeps which may contain phony files to minimize ninja.
+func (f *flagExporter) addExportedGeneratedHeaders(headers ...android.Path) {
+ f.headers = append(f.headers, headers...)
+}
+
func (f *flagExporter) exportedDirs() android.Paths {
return f.dirs
}
@@ -296,11 +304,16 @@
return f.deps
}
+func (f *flagExporter) exportedGeneratedHeaders() android.Paths {
+ return f.headers
+}
+
type exportedFlagsProducer interface {
exportedDirs() android.Paths
exportedSystemDirs() android.Paths
exportedFlags() []string
exportedDeps() android.Paths
+ exportedGeneratedHeaders() android.Paths
}
var _ exportedFlagsProducer = (*flagExporter)(nil)
@@ -966,12 +979,16 @@
library.reexportSystemDirs(deps.ReexportedSystemDirs...)
library.reexportFlags(deps.ReexportedFlags...)
library.reexportDeps(deps.ReexportedDeps...)
+ library.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
if Bool(library.Properties.Aidl.Export_aidl_headers) {
if library.baseCompiler.hasSrcExt(".aidl") {
dir := android.PathForModuleGen(ctx, "aidl")
library.reexportDirs(dir)
- library.reexportDeps(library.baseCompiler.pathDeps...) // TODO: restrict to aidl deps
+
+ // TODO: restrict to aidl deps
+ library.reexportDeps(library.baseCompiler.pathDeps...)
+ library.addExportedGeneratedHeaders(library.baseCompiler.pathDeps...)
}
}
@@ -983,7 +1000,10 @@
}
includes = append(includes, flags.proto.Dir)
library.reexportDirs(includes...)
- library.reexportDeps(library.baseCompiler.pathDeps...) // TODO: restrict to proto deps
+
+ // TODO: restrict to proto deps
+ library.reexportDeps(library.baseCompiler.pathDeps...)
+ library.addExportedGeneratedHeaders(library.baseCompiler.pathDeps...)
}
}
@@ -1001,6 +1021,7 @@
library.reexportDirs(dir)
library.reexportDeps(library.baseCompiler.pathDeps...)
+ library.addExportedGeneratedHeaders(library.baseCompiler.pathDeps...)
}
if library.buildStubs() {
@@ -1403,3 +1424,230 @@
return outputFile
}
+
+var LibrarySdkMemberType = &librarySdkMemberType{}
+
+type librarySdkMemberType struct {
+}
+
+func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+ targets := mctx.MultiTargets()
+ for _, lib := range names {
+ for _, target := range targets {
+ name, version := StubsLibNameAndVersion(lib)
+ if version == "" {
+ version = LatestStubsVersionFor(mctx.Config(), name)
+ }
+ mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+ {Mutator: "image", Variation: android.CoreVariation},
+ {Mutator: "link", Variation: "shared"},
+ {Mutator: "version", Variation: version},
+ }...), dependencyTag, name)
+ }
+ }
+}
+
+func (mt *librarySdkMemberType) IsInstance(module android.Module) bool {
+ _, ok := module.(*Module)
+ return ok
+}
+
+// copy exported header files and stub *.so files
+func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+ info := organizeVariants(member)
+ buildSharedNativeLibSnapshot(sdkModuleContext, info, builder, member)
+}
+
+func buildSharedNativeLibSnapshot(sdkModuleContext android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder, member android.SdkMember) {
+ // a function for emitting include dirs
+ printExportedDirCopyCommandsForNativeLibs := func(lib archSpecificNativeLibInfo) {
+ includeDirs := lib.exportedIncludeDirs
+ includeDirs = append(includeDirs, lib.exportedSystemIncludeDirs...)
+ if len(includeDirs) == 0 {
+ return
+ }
+ for _, dir := range includeDirs {
+ if _, gen := dir.(android.WritablePath); gen {
+ // generated headers are copied via exportedGeneratedHeaders. See below.
+ continue
+ }
+ targetDir := nativeIncludeDir
+ if info.hasArchSpecificFlags {
+ targetDir = filepath.Join(lib.archType, targetDir)
+ }
+
+ // TODO(jiyong) copy headers having other suffixes
+ headers, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.h", nil)
+ for _, file := range headers {
+ src := android.PathForSource(sdkModuleContext, file)
+ dest := filepath.Join(targetDir, file)
+ builder.CopyToSnapshot(src, dest)
+ }
+ }
+
+ genHeaders := lib.exportedGeneratedHeaders
+ for _, file := range genHeaders {
+ targetDir := nativeGeneratedIncludeDir
+ if info.hasArchSpecificFlags {
+ targetDir = filepath.Join(lib.archType, targetDir)
+ }
+ dest := filepath.Join(targetDir, lib.name, file.Rel())
+ builder.CopyToSnapshot(file, dest)
+ }
+ }
+
+ if !info.hasArchSpecificFlags {
+ printExportedDirCopyCommandsForNativeLibs(info.archVariants[0])
+ }
+
+ // for each architecture
+ for _, av := range info.archVariants {
+ builder.CopyToSnapshot(av.outputFile, nativeStubFilePathFor(av))
+
+ if info.hasArchSpecificFlags {
+ printExportedDirCopyCommandsForNativeLibs(av)
+ }
+ }
+
+ info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
+}
+
+func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+
+ // a function for emitting include dirs
+ addExportedDirsForNativeLibs := func(lib archSpecificNativeLibInfo, properties android.BpPropertySet, systemInclude bool) {
+ includeDirs := nativeIncludeDirPathsFor(lib, systemInclude, info.hasArchSpecificFlags)
+ if len(includeDirs) == 0 {
+ return
+ }
+ var propertyName string
+ if !systemInclude {
+ propertyName = "export_include_dirs"
+ } else {
+ propertyName = "export_system_include_dirs"
+ }
+ properties.AddProperty(propertyName, includeDirs)
+ }
+
+ pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_library_shared")
+
+ if !info.hasArchSpecificFlags {
+ addExportedDirsForNativeLibs(info.archVariants[0], pbm, false /*systemInclude*/)
+ addExportedDirsForNativeLibs(info.archVariants[0], pbm, true /*systemInclude*/)
+ }
+
+ archProperties := pbm.AddPropertySet("arch")
+ for _, av := range info.archVariants {
+ archTypeProperties := archProperties.AddPropertySet(av.archType)
+ archTypeProperties.AddProperty("srcs", []string{nativeStubFilePathFor(av)})
+ if info.hasArchSpecificFlags {
+ // export_* properties are added inside the arch: {<arch>: {...}} block
+ addExportedDirsForNativeLibs(av, archTypeProperties, false /*systemInclude*/)
+ addExportedDirsForNativeLibs(av, archTypeProperties, true /*systemInclude*/)
+ }
+ }
+ pbm.AddProperty("stl", "none")
+ pbm.AddProperty("system_shared_libs", []string{})
+}
+
+const (
+ nativeIncludeDir = "include"
+ nativeGeneratedIncludeDir = "include_gen"
+ nativeStubDir = "lib"
+ nativeStubFileSuffix = ".so"
+)
+
+// path to the stub file of a native shared library. Relative to <sdk_root>/<api_dir>
+func nativeStubFilePathFor(lib archSpecificNativeLibInfo) string {
+ return filepath.Join(lib.archType,
+ nativeStubDir, lib.name+nativeStubFileSuffix)
+}
+
+// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
+func nativeIncludeDirPathsFor(lib archSpecificNativeLibInfo, systemInclude bool, archSpecific bool) []string {
+ var result []string
+ var includeDirs []android.Path
+ if !systemInclude {
+ includeDirs = lib.exportedIncludeDirs
+ } else {
+ includeDirs = lib.exportedSystemIncludeDirs
+ }
+ for _, dir := range includeDirs {
+ var path string
+ if _, gen := dir.(android.WritablePath); gen {
+ path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
+ } else {
+ path = filepath.Join(nativeIncludeDir, dir.String())
+ }
+ if archSpecific {
+ path = filepath.Join(lib.archType, path)
+ }
+ result = append(result, path)
+ }
+ return result
+}
+
+// archSpecificNativeLibInfo represents an arch-specific variant of a native lib
+type archSpecificNativeLibInfo struct {
+ name string
+ archType string
+ exportedIncludeDirs android.Paths
+ exportedSystemIncludeDirs android.Paths
+ exportedFlags []string
+ exportedGeneratedHeaders android.Paths
+ outputFile android.Path
+}
+
+func (lib *archSpecificNativeLibInfo) signature() string {
+ return fmt.Sprintf("%v %v %v %v",
+ lib.name,
+ lib.exportedIncludeDirs.Strings(),
+ lib.exportedSystemIncludeDirs.Strings(),
+ lib.exportedFlags)
+}
+
+// nativeLibInfo represents a collection of arch-specific modules having the same name
+type nativeLibInfo struct {
+ name string
+ archVariants []archSpecificNativeLibInfo
+ // hasArchSpecificFlags is set to true if modules for each architecture all have the same
+ // include dirs, flags, etc, in which case only those of the first arch is selected.
+ hasArchSpecificFlags bool
+}
+
+// Organize the variants by architecture.
+func organizeVariants(member android.SdkMember) *nativeLibInfo {
+ info := &nativeLibInfo{name: member.Name()}
+
+ for _, variant := range member.Variants() {
+ ccModule := variant.(*Module)
+
+ info.archVariants = append(info.archVariants, archSpecificNativeLibInfo{
+ name: ccModule.BaseModuleName(),
+ archType: ccModule.Target().Arch.ArchType.String(),
+ exportedIncludeDirs: ccModule.ExportedIncludeDirs(),
+ exportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
+ exportedFlags: ccModule.ExportedFlags(),
+ exportedGeneratedHeaders: ccModule.ExportedGeneratedHeaders(),
+ outputFile: ccModule.OutputFile().Path(),
+ })
+ }
+
+ // Determine if include dirs and flags for each variant are different across arch-specific
+ // variants or not. And set hasArchSpecificFlags accordingly
+ // by default, include paths and flags are assumed to be the same across arches
+ info.hasArchSpecificFlags = false
+ oldSignature := ""
+ for _, av := range info.archVariants {
+ newSignature := av.signature()
+ if oldSignature == "" {
+ oldSignature = newSignature
+ }
+ if oldSignature != newSignature {
+ info.hasArchSpecificFlags = true
+ break
+ }
+ }
+
+ return info
+}
diff --git a/cc/makevars.go b/cc/makevars.go
index e8cedf0..0f9f4c1 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -147,6 +147,7 @@
ctx.Strict("WITH_TIDY_FLAGS", "${config.TidyWithTidyFlags}")
ctx.Strict("AIDL_CPP", "${aidlCmd}")
+ ctx.Strict("ALLOWED_MANUAL_INTERFACE_PATHS", strings.Join(allowedManualInterfacePaths, " "))
ctx.Strict("M4", "${m4Cmd}")
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index 4e6cdd7..32676d6 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -90,6 +90,7 @@
p.libraryDecorator.reexportSystemDirs(deps.ReexportedSystemDirs...)
p.libraryDecorator.reexportFlags(deps.ReexportedFlags...)
p.libraryDecorator.reexportDeps(deps.ReexportedDeps...)
+ p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
builderFlags := flagsToBuilderFlags(flags)
diff --git a/cc/rs.go b/cc/rs.go
index 61fd1a8..9149e17 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -29,7 +29,7 @@
// Use RenderScript prebuilts for unbundled builds but not PDK builds
return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "bin/llvm-rs-cc")
} else {
- return pctx.HostBinToolPath(ctx, "llvm-rs-cc").String()
+ return ctx.Config().HostToolPath(ctx, "llvm-rs-cc").String()
}
})
}
diff --git a/cc/testing.go b/cc/testing.go
index 3b10f87..18cc83f 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -271,7 +271,6 @@
ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("image", android.ImageMutator).Parallel()
ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("vndk", VndkMutator).Parallel()
ctx.BottomUp("version", VersionMutator).Parallel()
diff --git a/cc/vndk.go b/cc/vndk.go
index f25861a..5aeb2e6 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -704,7 +704,7 @@
// We glob headers from include directories inside source tree. So we first gather
// all include directories inside our source tree. On the contrast, we manually
// collect generated headers from dependencies as they can't globbed.
- generatedHeaders = append(generatedHeaders, l.exportedDeps()...)
+ generatedHeaders = append(generatedHeaders, l.exportedGeneratedHeaders()...)
for _, dir := range append(l.exportedDirs(), l.exportedSystemDirs()...) {
exportedIncludes[dir.String()] = true
}
diff --git a/cmd/multiproduct_kati/Android.bp b/cmd/multiproduct_kati/Android.bp
index 13b3679..d34f8c3 100644
--- a/cmd/multiproduct_kati/Android.bp
+++ b/cmd/multiproduct_kati/Android.bp
@@ -24,4 +24,7 @@
srcs: [
"main.go",
],
+ testSrcs: [
+ "main_test.go",
+ ],
}
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 2800ade..4771206 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -64,6 +64,9 @@
var skipProducts = flag.String("skip-products", "", "comma-separated list of products to skip (known failures, etc)")
var includeProducts = flag.String("products", "", "comma-separated list of products to build")
+var shardCount = flag.Int("shard-count", 1, "split the products into multiple shards (to spread the build onto multiple machines, etc)")
+var shard = flag.Int("shard", 1, "1-indexed shard to execute")
+
const errorLeadingLines = 20
const errorTrailingLines = 20
@@ -278,6 +281,17 @@
}
}
+ if *shard < 1 {
+ log.Fatalf("--shard value must be >= 1, not %d\n", *shard)
+ } else if *shardCount < 1 {
+ log.Fatalf("--shard-count value must be >= 1, not %d\n", *shardCount)
+ } else if *shard > *shardCount {
+ log.Fatalf("--shard (%d) must not be greater than --shard-count (%d)\n", *shard,
+ *shardCount)
+ } else if *shardCount > 1 {
+ finalProductsList = splitList(finalProductsList, *shardCount)[*shard-1]
+ }
+
log.Verbose("Got product list: ", finalProductsList)
s := buildCtx.Status.StartTool()
@@ -472,3 +486,18 @@
// discard writes
return len(p), nil
}
+
+func splitList(list []string, shardCount int) (ret [][]string) {
+ each := len(list) / shardCount
+ extra := len(list) % shardCount
+ for i := 0; i < shardCount; i++ {
+ count := each
+ if extra > 0 {
+ count += 1
+ extra -= 1
+ }
+ ret = append(ret, list[:count])
+ list = list[count:]
+ }
+ return
+}
diff --git a/cmd/multiproduct_kati/main_test.go b/cmd/multiproduct_kati/main_test.go
new file mode 100644
index 0000000..263a124
--- /dev/null
+++ b/cmd/multiproduct_kati/main_test.go
@@ -0,0 +1,93 @@
+// 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 main
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+)
+
+func TestSplitList(t *testing.T) {
+ testcases := []struct {
+ inputCount int
+ shardCount int
+ want [][]string
+ }{
+ {
+ inputCount: 1,
+ shardCount: 1,
+ want: [][]string{{"1"}},
+ },
+ {
+ inputCount: 1,
+ shardCount: 2,
+ want: [][]string{{"1"}, {}},
+ },
+ {
+ inputCount: 4,
+ shardCount: 2,
+ want: [][]string{{"1", "2"}, {"3", "4"}},
+ },
+ {
+ inputCount: 19,
+ shardCount: 10,
+ want: [][]string{
+ {"1", "2"},
+ {"3", "4"},
+ {"5", "6"},
+ {"7", "8"},
+ {"9", "10"},
+ {"11", "12"},
+ {"13", "14"},
+ {"15", "16"},
+ {"17", "18"},
+ {"19"},
+ },
+ },
+ {
+ inputCount: 15,
+ shardCount: 10,
+ want: [][]string{
+ {"1", "2"},
+ {"3", "4"},
+ {"5", "6"},
+ {"7", "8"},
+ {"9", "10"},
+ {"11"},
+ {"12"},
+ {"13"},
+ {"14"},
+ {"15"},
+ },
+ },
+ }
+
+ for _, tc := range testcases {
+ t.Run(fmt.Sprintf("%d/%d", tc.inputCount, tc.shardCount), func(t *testing.T) {
+ input := []string{}
+ for i := 1; i <= tc.inputCount; i++ {
+ input = append(input, fmt.Sprintf("%d", i))
+ }
+
+ got := splitList(input, tc.shardCount)
+
+ if !reflect.DeepEqual(got, tc.want) {
+ t.Errorf("unexpected result for splitList([]string{...%d...}, %d):\nwant: %v\n got: %v\n",
+ tc.inputCount, tc.shardCount, tc.want, got)
+ }
+ })
+ }
+}
diff --git a/cuj/Android.bp b/cuj/Android.bp
new file mode 100644
index 0000000..21d667f
--- /dev/null
+++ b/cuj/Android.bp
@@ -0,0 +1,12 @@
+blueprint_go_binary {
+ name: "cuj_tests",
+ deps: [
+ "soong-ui-build",
+ "soong-ui-logger",
+ "soong-ui-terminal",
+ "soong-ui-tracer",
+ ],
+ srcs: [
+ "cuj.go",
+ ],
+}
diff --git a/cuj/cuj.go b/cuj/cuj.go
new file mode 100644
index 0000000..c7ff8ff
--- /dev/null
+++ b/cuj/cuj.go
@@ -0,0 +1,190 @@
+// 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 executable runs a series of build commands to test and benchmark some critical user journeys.
+package main
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+ "time"
+
+ "android/soong/ui/build"
+ "android/soong/ui/logger"
+ "android/soong/ui/metrics"
+ "android/soong/ui/status"
+ "android/soong/ui/terminal"
+ "android/soong/ui/tracer"
+)
+
+type Test struct {
+ name string
+ args []string
+
+ results TestResults
+}
+
+type TestResults struct {
+ metrics *metrics.Metrics
+ err error
+}
+
+// Run runs a single build command. It emulates the "m" command line by calling into Soong UI directly.
+func (t *Test) Run(logsDir string) {
+ output := terminal.NewStatusOutput(os.Stdout, "", false, false)
+
+ log := logger.New(output)
+ defer log.Cleanup()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+
+ trace := tracer.New(log)
+ defer trace.Close()
+
+ met := metrics.New()
+
+ stat := &status.Status{}
+ defer stat.Finish()
+ stat.AddOutput(output)
+ stat.AddOutput(trace.StatusTracer())
+
+ build.SetupSignals(log, cancel, func() {
+ trace.Close()
+ log.Cleanup()
+ stat.Finish()
+ })
+
+ buildCtx := build.Context{ContextImpl: &build.ContextImpl{
+ Context: ctx,
+ Logger: log,
+ Metrics: met,
+ Tracer: trace,
+ Writer: output,
+ Status: stat,
+ }}
+
+ defer logger.Recover(func(err error) {
+ t.results.err = err
+ })
+
+ config := build.NewConfig(buildCtx, t.args...)
+ build.SetupOutDir(buildCtx, config)
+
+ os.MkdirAll(logsDir, 0777)
+ log.SetOutput(filepath.Join(logsDir, "soong.log"))
+ trace.SetOutput(filepath.Join(logsDir, "build.trace"))
+ stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, "verbose.log")))
+ stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, "error.log")))
+ stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, "build_error")))
+ stat.AddOutput(status.NewCriticalPath(log))
+
+ defer met.Dump(filepath.Join(logsDir, "soong_metrics"))
+
+ if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
+ if !strings.HasSuffix(start, "N") {
+ if start_time, err := strconv.ParseUint(start, 10, 64); err == nil {
+ log.Verbosef("Took %dms to start up.",
+ time.Since(time.Unix(0, int64(start_time))).Nanoseconds()/time.Millisecond.Nanoseconds())
+ buildCtx.CompleteTrace(metrics.RunSetupTool, "startup", start_time, uint64(time.Now().UnixNano()))
+ }
+ }
+
+ if executable, err := os.Executable(); err == nil {
+ trace.ImportMicrofactoryLog(filepath.Join(filepath.Dir(executable), "."+filepath.Base(executable)+".trace"))
+ }
+ }
+
+ f := build.NewSourceFinder(buildCtx, config)
+ defer f.Shutdown()
+ build.FindSources(buildCtx, config, f)
+
+ build.Build(buildCtx, config, build.BuildAll)
+
+ t.results.metrics = met
+}
+
+func main() {
+ outDir := os.Getenv("OUT_DIR")
+ if outDir == "" {
+ outDir = "out"
+ }
+
+ cujDir := filepath.Join(outDir, "cuj_tests")
+
+ // Use a subdirectory for the out directory for the tests to keep them isolated.
+ os.Setenv("OUT_DIR", filepath.Join(cujDir, "out"))
+
+ // Each of these tests is run in sequence without resetting the output tree. The state of the output tree will
+ // affect each successive test. To maintain the validity of the benchmarks across changes, care must be taken
+ // to avoid changing the state of the tree when a test is run. This is most easily accomplished by adding tests
+ // at the end.
+ tests := []Test{
+ {
+ // Reset the out directory to get reproducible results.
+ name: "clean",
+ args: []string{"clean"},
+ },
+ {
+ // Parse the build files.
+ name: "nothing",
+ args: []string{"nothing"},
+ },
+ {
+ // Parse the build files again to monitor issues like globs rerunning.
+ name: "nothing_rebuild",
+ args: []string{"nothing"},
+ },
+ {
+ // Parse the build files again, this should always be very short.
+ name: "nothing_rebuild_twice",
+ args: []string{"nothing"},
+ },
+ {
+ // Build the framework as a common developer task and one that keeps getting longer.
+ name: "framework",
+ args: []string{"framework"},
+ },
+ {
+ // Build the framework again to make sure it doesn't rebuild anything.
+ name: "framework_rebuild",
+ args: []string{"framework"},
+ },
+ {
+ // Build the framework again to make sure it doesn't rebuild anything even if it did the second time.
+ name: "framework_rebuild_twice",
+ args: []string{"framework"},
+ },
+ }
+
+ cujMetrics := metrics.NewCriticalUserJourneysMetrics()
+ defer cujMetrics.Dump(filepath.Join(cujDir, "logs", "cuj_metrics.pb"))
+
+ for i, t := range tests {
+ logsSubDir := fmt.Sprintf("%02d_%s", i, t.name)
+ logsDir := filepath.Join(cujDir, "logs", logsSubDir)
+ t.Run(logsDir)
+ if t.results.err != nil {
+ fmt.Printf("error running test %q: %s\n", t.name, t.results.err)
+ break
+ }
+ if t.results.metrics != nil {
+ cujMetrics.Add(t.name, t.results.metrics)
+ }
+ }
+}
diff --git a/cuj/run_cuj_tests.sh b/cuj/run_cuj_tests.sh
new file mode 100755
index 0000000..b4f9f88
--- /dev/null
+++ b/cuj/run_cuj_tests.sh
@@ -0,0 +1,29 @@
+#!/bin/bash -e
+
+readonly UNAME="$(uname)"
+case "$UNAME" in
+Linux)
+ readonly OS='linux'
+ ;;
+Darwin)
+ readonly OS='darwin'
+ ;;
+*)
+ echo "Unsupported OS '$UNAME'"
+ exit 1
+ ;;
+esac
+
+readonly ANDROID_TOP="$(cd $(dirname $0)/../../..; pwd)"
+cd "$ANDROID_TOP"
+
+export OUT_DIR="${OUT_DIR:-out}"
+readonly SOONG_OUT="${OUT_DIR}/soong"
+
+build/soong/soong_ui.bash --make-mode "${SOONG_OUT}/host/${OS}-x86/bin/cuj_tests"
+
+"${SOONG_OUT}/host/${OS}-x86/bin/cuj_tests" || true
+
+if [ -n "${DIST_DIR}" ]; then
+ cp -r "${OUT_DIR}/cuj_tests/logs" "${DIST_DIR}"
+fi
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 35c2b44..83e3673 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -41,7 +41,7 @@
BootJars []string // modules for jars that form the boot class path
UpdatableBootJars []string // jars within apex that form the boot class path
- ArtApexJars []string // modules for jars that are in the ART APEX
+ ArtApexJars []string // modules for jars that are in the ART APEX
SystemServerJars []string // jars that form the system server
SystemServerApps []string // apps that are loaded into system server
@@ -117,9 +117,10 @@
UsesLibraries []string
LibraryPaths map[string]android.Path
- Archs []android.ArchType
- DexPreoptImages []android.Path
- DexPreoptImagesDeps []android.Paths
+ Archs []android.ArchType
+ DexPreoptImages []android.Path
+ DexPreoptImagesDeps []android.OutputPaths
+ DexPreoptImageLocations []string
PreoptBootClassPathDexFiles android.Paths // file paths of boot class path files
PreoptBootClassPathDexLocations []string // virtual locations of boot class path files
@@ -225,6 +226,7 @@
ProfileClassListing string
LibraryPaths map[string]string
DexPreoptImages []string
+ DexPreoptImageLocations []string
PreoptBootClassPathDexFiles []string
}
@@ -242,10 +244,11 @@
config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing))
config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths)
config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages)
+ config.ModuleConfig.DexPreoptImageLocations = config.DexPreoptImageLocations
config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles)
// This needs to exist, but dependencies are already handled in Make, so we don't need to pass them through JSON.
- config.ModuleConfig.DexPreoptImagesDeps = make([]android.Paths, len(config.ModuleConfig.DexPreoptImages))
+ config.ModuleConfig.DexPreoptImagesDeps = make([]android.OutputPaths, len(config.ModuleConfig.DexPreoptImages))
return config.ModuleConfig, nil
}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index f3bf2ff..ee04dfd 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -86,10 +86,8 @@
generateDM := shouldGenerateDM(module, global)
- for i, arch := range module.Archs {
- image := module.DexPreoptImages[i]
- imageDeps := module.DexPreoptImagesDeps[i]
- dexpreoptCommand(ctx, global, module, rule, arch, profile, image, imageDeps, appImage, generateDM)
+ for archIdx, _ := range module.Archs {
+ dexpreoptCommand(ctx, global, module, rule, archIdx, profile, appImage, generateDM)
}
}
}
@@ -193,7 +191,9 @@
}
func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder,
- arch android.ArchType, profile, bootImage android.Path, bootImageDeps android.Paths, appImage, generateDM bool) {
+ archIdx int, profile android.WritablePath, appImage bool, generateDM bool) {
+
+ arch := module.Archs[archIdx]
// HACK: make soname in Soong-generated .odex files match Make.
base := filepath.Base(module.DexLocation)
@@ -222,13 +222,6 @@
invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
- // 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 != nil {
- bootImageLocation = PathToLocation(bootImage, arch)
- }
-
// The class loader context using paths in the build
var classLoaderContextHost android.Paths
@@ -356,7 +349,7 @@
Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":").
Flag("${class_loader_context_arg}").
Flag("${stored_class_loader_context_arg}").
- FlagWithArg("--boot-image=", bootImageLocation).Implicits(bootImageDeps).
+ FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocations, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()).
FlagWithInput("--dex-file=", module.DexPath).
FlagWithArg("--dex-location=", dexLocationArg).
FlagWithOutput("--oat-file=", odexPath).ImplicitOutput(vdexPath).
@@ -502,8 +495,7 @@
}
for _, f := range global.PatternsOnSystemOther {
- // See comment of SYSTEM_OTHER_ODEX_FILTER for details on the matching.
- if makefileMatch("/"+f, dexLocation) || makefileMatch(filepath.Join(SystemPartition, f), dexLocation) {
+ if makefileMatch(filepath.Join(SystemPartition, f), dexLocation) {
return true
}
}
@@ -555,9 +547,9 @@
}
// Expected format for apexJarValue = <apex name>:<jar name>
-func GetJarLocationFromApexJarPair(apexJarValue string) (string) {
+func GetJarLocationFromApexJarPair(apexJarValue string) string {
apex, jar := SplitApexJarPair(apexJarValue)
- return filepath.Join("/apex", apex, "javalib", jar + ".jar")
+ return filepath.Join("/apex", apex, "javalib", jar+".jar")
}
func contains(l []string, s string) bool {
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 6f8120e..3264d6a 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -49,7 +49,8 @@
LibraryPaths: nil,
Archs: []android.ArchType{android.Arm},
DexPreoptImages: android.Paths{android.PathForTesting("system/framework/arm/boot.art")},
- DexPreoptImagesDeps: []android.Paths{android.Paths{}},
+ DexPreoptImagesDeps: []android.OutputPaths{android.OutputPaths{}},
+ DexPreoptImageLocations: []string{},
PreoptBootClassPathDexFiles: nil,
PreoptBootClassPathDexLocations: nil,
PreoptExtractedApk: false,
@@ -103,12 +104,13 @@
{module: productModule, expectedPartition: "product"},
},
},
+ // product/app/% only applies to product apps inside the system partition
{
patterns: []string{"app/%", "product/app/%"},
moduleTests: []moduleTest{
{module: systemModule, expectedPartition: "system_other/system"},
{module: systemProductModule, expectedPartition: "system_other/system/product"},
- {module: productModule, expectedPartition: "system_other/product"},
+ {module: productModule, expectedPartition: "product"},
},
},
}
@@ -128,7 +130,7 @@
}
if rule.Installs().String() != wantInstalls.String() {
- t.Errorf("\npatterns: %v\nwant installs:\n %v\ngot:\n %v", test.patterns, wantInstalls, rule.Installs())
+ t.Errorf("\nwant installs:\n %v\ngot:\n %v", wantInstalls, rule.Installs())
}
}
}
diff --git a/docs/best_practices.md b/docs/best_practices.md
index 93be319..bc760b8 100644
--- a/docs/best_practices.md
+++ b/docs/best_practices.md
@@ -240,8 +240,8 @@
In cases where the names cannot be made unique a `soong_namespace` should be
used to partition a set of modules so that they are built only when the
namespace is listed in `PRODUCT_SOONG_NAMESPACES`. See the
-[Name resolution](../README.md#name-resolution) section of the Soong README.md
-for more on namespaces.
+[Referencing Modules](../README.md#referencing-modules) section of the Soong
+README.md for more on namespaces.
### Module with name based on variable
diff --git a/java/app_test.go b/java/app_test.go
index fc8cf8e..c7ed49b 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -175,6 +175,95 @@
`)
}
+func TestAndroidAppLinkType(t *testing.T) {
+ testJava(t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ static_libs: ["baz"],
+ platform_apis: true,
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["b.java"],
+ }
+
+ android_library {
+ name: "baz",
+ sdk_version: "system_current",
+ srcs: ["c.java"],
+ }
+ `)
+
+ testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ sdk_version: "current",
+ static_libs: ["baz"],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["b.java"],
+ }
+
+ android_library {
+ name: "baz",
+ sdk_version: "system_current",
+ srcs: ["c.java"],
+ }
+ `)
+
+ testJava(t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ sdk_version: "system_current",
+ static_libs: ["baz"],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["b.java"],
+ }
+
+ android_library {
+ name: "baz",
+ sdk_version: "system_current",
+ srcs: ["c.java"],
+ }
+ `)
+
+ testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ sdk_version: "system_current",
+ static_libs: ["baz"],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["b.java"],
+ }
+
+ android_library {
+ name: "baz",
+ srcs: ["c.java"],
+ }
+ `)
+}
+
func TestResourceDirs(t *testing.T) {
testCases := []struct {
name string
diff --git a/java/config/config.go b/java/config/config.go
index 333de32..fee6341 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -124,7 +124,7 @@
if ctx.Config().UnbundledBuild() {
return "prebuilts/build-tools/common/framework/" + turbine
} else {
- return pctx.HostJavaToolPath(ctx, turbine).String()
+ return ctx.Config().HostJavaToolPath(ctx, turbine).String()
}
})
@@ -170,7 +170,7 @@
if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "bin", tool)
} else {
- return pctx.HostBinToolPath(ctx, tool).String()
+ return ctx.Config().HostToolPath(ctx, tool).String()
}
})
}
@@ -180,7 +180,7 @@
if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
return filepath.Join("prebuilts/sdk/tools/lib", tool+".jar")
} else {
- return pctx.HostJavaToolPath(ctx, tool+".jar").String()
+ return ctx.Config().HostJavaToolPath(ctx, tool+".jar").String()
}
})
}
@@ -194,7 +194,7 @@
}
return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "lib64", tool+ext)
} else {
- return pctx.HostJNIToolPath(ctx, tool).String()
+ return ctx.Config().HostJNIToolPath(ctx, tool).String()
}
})
}
@@ -204,7 +204,7 @@
if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
return filepath.Join("prebuilts/build-tools", ctx.Config().PrebuiltOS(), "bin", tool)
} else {
- return pctx.HostBinToolPath(ctx, tool).String()
+ return ctx.Config().HostToolPath(ctx, tool).String()
}
})
}
diff --git a/java/dex.go b/java/dex.go
index 5b25b21..cd6d90d 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -115,7 +115,6 @@
r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars"))
r8Flags = append(r8Flags, flags.classpath.FormJavaClassPath("-libraryjars"))
- r8Flags = append(r8Flags, "-forceprocessing")
r8Deps = append(r8Deps, proguardRaiseDeps...)
r8Deps = append(r8Deps, flags.bootClasspath...)
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 2b1c994..479dec6 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -124,7 +124,7 @@
}
var images android.Paths
- var imagesDeps []android.Paths
+ var imagesDeps []android.OutputPaths
for _, arch := range archs {
images = append(images, bootImage.images[arch])
imagesDeps = append(imagesDeps, bootImage.imagesDeps[arch])
@@ -169,15 +169,16 @@
UsesLibraries: d.usesLibs,
LibraryPaths: d.libraryPaths,
- Archs: archs,
- DexPreoptImages: images,
- DexPreoptImagesDeps: imagesDeps,
+ Archs: archs,
+ DexPreoptImages: images,
+ DexPreoptImagesDeps: imagesDeps,
+ DexPreoptImageLocations: bootImage.imageLocations,
// We use the dex paths and dex locations of the default boot image, as it
// contains the full dexpreopt boot classpath. Other images may just contain a subset of
// the dexpreopt boot classpath.
- PreoptBootClassPathDexFiles: defaultBootImage.dexPaths.Paths(),
- PreoptBootClassPathDexLocations: defaultBootImage.dexLocations,
+ PreoptBootClassPathDexFiles: defaultBootImage.dexPathsDeps.Paths(),
+ PreoptBootClassPathDexLocations: defaultBootImage.dexLocationsDeps,
PreoptExtractedApk: false,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index a29665e..88e3bc2 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -22,7 +22,6 @@
"android/soong/android"
"android/soong/dexpreopt"
- "github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
)
@@ -50,38 +49,77 @@
// will then reconstruct the real path, so the rules must have a dependency on the real path.
type bootImageConfig struct {
- name string
- stem string
- modules []string
- dexLocations []string
- dexPaths android.WritablePaths
- dir android.OutputPath
- symbolsDir android.OutputPath
- targets []android.Target
- images map[android.ArchType]android.OutputPath
- imagesDeps map[android.ArchType]android.Paths
- zip android.WritablePath
+ // Whether this image is an extension.
+ extension bool
+
+ // Image name (used in directory names and ninja rule names).
+ name string
+
+ // Basename of the image: the resulting filenames are <stem>[-<jar>].{art,oat,vdex}.
+ stem string
+
+ // Output directory for the image files.
+ dir android.OutputPath
+
+ // Output directory for the image files with debug symbols.
+ symbolsDir android.OutputPath
+
+ // Subdirectory where the image files are installed.
+ installSubdir string
+
+ // Targets for which the image is generated.
+ targets []android.Target
+
+ // The names of jars that constitute this image.
+ modules []string
+
+ // The "locations" of jars.
+ dexLocations []string // for this image
+ dexLocationsDeps []string // for the dependency images and in this image
+
+ // File paths to jars.
+ dexPaths android.WritablePaths // for this image
+ dexPathsDeps android.WritablePaths // for the dependency images and in this image
+
+ // The "locations" of the dependency images and in this image.
+ imageLocations []string
+
+ // Paths to image files (grouped by target).
+ images map[android.ArchType]android.OutputPath // first image file
+ imagesDeps map[android.ArchType]android.OutputPaths // all files
+
+ // File path to a zip archive with all image files (or nil, if not needed).
+ zip android.WritablePath
}
-func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) []android.OutputPath {
- ret := make([]android.OutputPath, 0, len(image.modules)*len(exts))
-
- // dex preopt on the bootclasspath produces multiple files. The first dex file
- // is converted into to 'name'.art (to match the legacy assumption that 'name'.art
+func (image bootImageConfig) moduleName(idx int) string {
+ // Dexpreopt on the boot class path produces multiple files. The first dex file
+ // is converted into 'name'.art (to match the legacy assumption that 'name'.art
// exists), and the rest are converted to 'name'-<jar>.art.
- // In addition, each .art file has an associated .oat and .vdex file, and an
- // unstripped .oat file
- for i, m := range image.modules {
- name := image.stem
- if i != 0 {
- name += "-" + stemOf(m)
- }
+ m := image.modules[idx]
+ name := image.stem
+ if idx != 0 || image.extension {
+ name += "-" + stemOf(m)
+ }
+ return name
+}
+func (image bootImageConfig) firstModuleNameOrStem() string {
+ if len(image.modules) > 0 {
+ return image.moduleName(0)
+ } else {
+ return image.stem
+ }
+}
+
+func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) android.OutputPaths {
+ ret := make(android.OutputPaths, 0, len(image.modules)*len(exts))
+ for i := range image.modules {
+ name := image.moduleName(i)
for _, ext := range exts {
ret = append(ret, dir.Join(ctx, name+ext))
}
}
-
return ret
}
@@ -140,12 +178,6 @@
return false
}
-func skipDexpreoptArtBootJars(ctx android.BuilderContext) bool {
- // with EMMA_INSTRUMENT_FRAMEWORK=true ART boot class path libraries have dependencies on framework,
- // therefore dexpreopt ART libraries cannot be dexpreopted in isolation => no ART boot image
- return ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK")
-}
-
type dexpreoptBootJars struct {
defaultBootImage *bootImage
otherImages []*bootImage
@@ -154,8 +186,8 @@
}
// Accessor function for the apex package. Returns nil if dexpreopt is disabled.
-func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]android.Paths {
- if skipDexpreoptBootJars(ctx) || skipDexpreoptArtBootJars(ctx) {
+func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]android.OutputPaths {
+ if skipDexpreoptBootJars(ctx) {
return nil
}
return artBootImageConfig(ctx).imagesDeps
@@ -184,10 +216,8 @@
// Always create the default boot image first, to get a unique profile rule for all images.
d.defaultBootImage = buildBootImage(ctx, defaultBootImageConfig(ctx))
- if !skipDexpreoptArtBootJars(ctx) {
- // Create boot image for the ART apex (build artifacts are accessed via the global boot image config).
- buildBootImage(ctx, artBootImageConfig(ctx))
- }
+ // Create boot image for the ART apex (build artifacts are accessed via the global boot image config).
+ d.otherImages = append(d.otherImages, buildBootImage(ctx, artBootImageConfig(ctx)))
if global.GenerateApexImage {
// Create boot images for the JIT-zygote experiment.
d.otherImages = append(d.otherImages, buildBootImage(ctx, apexBootImageConfig(ctx)))
@@ -201,7 +231,6 @@
image := newBootImage(ctx, config)
bootDexJars := make(android.Paths, len(image.modules))
-
ctx.VisitAllModules(func(module android.Module) {
// Collect dex jar paths for the modules listed above.
if j, ok := module.(interface{ DexJar() android.Path }); ok {
@@ -265,11 +294,12 @@
global := dexpreoptGlobalConfig(ctx)
- symbolsDir := image.symbolsDir.Join(ctx, "system/framework", arch.String())
+ symbolsDir := image.symbolsDir.Join(ctx, image.installSubdir, arch.String())
symbolsFile := symbolsDir.Join(ctx, image.stem+".oat")
- outputDir := image.dir.Join(ctx, "system/framework", arch.String())
- outputPath := image.images[arch]
- oatLocation := pathtools.ReplaceExtension(dexpreopt.PathToLocation(outputPath, arch), "oat")
+ outputDir := image.dir.Join(ctx, image.installSubdir, arch.String())
+ outputPath := outputDir.Join(ctx, image.stem+".oat")
+ oatLocation := dexpreopt.PathToLocation(outputPath, arch)
+ imagePath := outputPath.ReplaceExtension(ctx, "art")
rule := android.NewRuleBuilder()
rule.MissingDeps(missingDeps)
@@ -312,18 +342,27 @@
cmd.FlagWithInput("--dirty-image-objects=", global.DirtyImageObjects.Path())
}
+ if image.extension {
+ artImage := artBootImageConfig(ctx).images[arch]
+ cmd.
+ Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
+ Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":").
+ FlagWithArg("--boot-image=", dexpreopt.PathToLocation(artImage, arch)).Implicit(artImage)
+ } else {
+ cmd.FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress())
+ }
+
cmd.
FlagForEachInput("--dex-file=", image.dexPaths.Paths()).
FlagForEachArg("--dex-location=", image.dexLocations).
Flag("--generate-debug-info").
Flag("--generate-build-id").
Flag("--image-format=lz4hc").
- FlagWithOutput("--oat-symbols=", symbolsFile).
+ FlagWithArg("--oat-symbols=", symbolsFile.String()).
Flag("--strip").
- FlagWithOutput("--oat-file=", outputPath.ReplaceExtension(ctx, "oat")).
+ FlagWithArg("--oat-file=", outputPath.String()).
FlagWithArg("--oat-location=", oatLocation).
- FlagWithOutput("--image=", outputPath).
- FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress()).
+ FlagWithArg("--image=", imagePath.String()).
FlagWithArg("--instruction-set=", arch.String()).
FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]).
FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]).
@@ -341,8 +380,8 @@
cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape(failureMessage))
- installDir := filepath.Join("/system/framework", arch.String())
- vdexInstallDir := filepath.Join("/system/framework")
+ installDir := filepath.Join("/", image.installSubdir, arch.String())
+ vdexInstallDir := filepath.Join("/", image.installSubdir)
var vdexInstalls android.RuleBuilderInstalls
var unstrippedInstalls android.RuleBuilderInstalls
@@ -425,8 +464,8 @@
Text(`ANDROID_LOG_TAGS="*:e"`).
Tool(tools.Profman).
FlagWithInput("--create-profile-from=", bootImageProfile).
- FlagForEachInput("--apk=", image.dexPaths.Paths()).
- FlagForEachArg("--dex-location=", image.dexLocations).
+ FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
+ FlagForEachArg("--dex-location=", image.dexLocationsDeps).
FlagWithOutput("--reference-profile-file=", profile)
rule.Install(profile, "/system/etc/boot-image.prof")
@@ -477,8 +516,8 @@
Tool(tools.Profman).
Flag("--generate-boot-profile").
FlagWithInput("--create-profile-from=", bootFrameworkProfile).
- FlagForEachInput("--apk=", image.dexPaths.Paths()).
- FlagForEachArg("--dex-location=", image.dexLocations).
+ FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
+ FlagForEachArg("--dex-location=", image.dexLocationsDeps).
FlagWithOutput("--reference-profile-file=", profile)
rule.Install(profile, "/system/etc/boot-image.bprof")
@@ -506,9 +545,9 @@
rule.Command().
// TODO: for now, use the debug version for better error reporting
BuiltTool(ctx, "oatdumpd").
- FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPaths.Paths(), ":").
- FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocations, ":").
- FlagWithArg("--image=", dexpreopt.PathToLocation(image.images[arch], arch)).Implicit(image.images[arch]).
+ FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
+ FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
+ FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps[arch].Paths()).
FlagWithOutput("--output=", output).
FlagWithArg("--instruction-set=", arch.String())
rule.Build(pctx, ctx, "dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String())
@@ -556,9 +595,9 @@
image := d.defaultBootImage
if image != nil {
ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
- ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPaths.Strings(), " "))
- ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocations, " "))
- ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+image.name, image.zip.String())
+ ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " "))
+ ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocationsDeps, " "))
+ ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS", strings.Join(image.imageLocations, ":"))
var imageNames []string
for _, current := range append(d.otherImages, image) {
@@ -579,6 +618,8 @@
if current.zip != nil {
}
}
+
+ ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String())
}
ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
}
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 29a5abe..87d5e30 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -48,7 +48,7 @@
pathCtx := android.PathContextForTesting(config, nil)
dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
- dexpreoptConfig.ArtApexJars = []string{"foo", "bar", "baz"}
+ dexpreoptConfig.BootJars = []string{"foo", "bar", "baz"}
setDexpreoptTestGlobalConfig(config, dexpreoptConfig)
ctx := testContext(bp, nil)
@@ -59,9 +59,10 @@
dexpreoptBootJars := ctx.SingletonForTests("dex_bootjars")
- bootArt := dexpreoptBootJars.Output("boot.art")
+ bootArt := dexpreoptBootJars.Output("boot-foo.art")
expectedInputs := []string{
+ "dex_artjars/apex/com.android.art/javalib/arm64/boot.art",
"dex_bootjars_input/foo.jar",
"dex_bootjars_input/bar.jar",
"dex_bootjars_input/baz.jar",
@@ -82,19 +83,19 @@
expectedOutputs := []string{
"dex_bootjars/system/framework/arm64/boot.invocation",
- "dex_bootjars/system/framework/arm64/boot.art",
+ "dex_bootjars/system/framework/arm64/boot-foo.art",
"dex_bootjars/system/framework/arm64/boot-bar.art",
"dex_bootjars/system/framework/arm64/boot-baz.art",
- "dex_bootjars/system/framework/arm64/boot.oat",
+ "dex_bootjars/system/framework/arm64/boot-foo.oat",
"dex_bootjars/system/framework/arm64/boot-bar.oat",
"dex_bootjars/system/framework/arm64/boot-baz.oat",
- "dex_bootjars/system/framework/arm64/boot.vdex",
+ "dex_bootjars/system/framework/arm64/boot-foo.vdex",
"dex_bootjars/system/framework/arm64/boot-bar.vdex",
"dex_bootjars/system/framework/arm64/boot-baz.vdex",
- "dex_bootjars_unstripped/system/framework/arm64/boot.oat",
+ "dex_bootjars_unstripped/system/framework/arm64/boot-foo.oat",
"dex_bootjars_unstripped/system/framework/arm64/boot-bar.oat",
"dex_bootjars_unstripped/system/framework/arm64/boot-baz.oat",
}
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 4dd7cfe..fd1cfd4 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -119,118 +119,148 @@
return modules
}
-// Construct a variant of the global config for dexpreopted bootclasspath jars. The variants differ
-// in the list of input jars (libcore, framework, or both), in the naming scheme for the dexpreopt
-// files (ART recognizes "apex" names as special), and whether to include a zip archive.
-//
-// 'name' is a string unique for each profile (used in directory names and ninja rule names)
-// 'stem' is the basename of the image: the resulting filenames are <stem>[-<jar>].{art,oat,vdex}.
-func getBootImageConfig(ctx android.PathContext, key android.OnceKey, name string, stem string,
- needZip bool, artApexJarsOnly bool) bootImageConfig {
+var (
+ bootImageConfigKey = android.NewOnceKey("bootImageConfig")
+ artBootImageName = "art"
+ frameworkBootImageName = "boot"
+ apexBootImageName = "apex"
+)
- return ctx.Config().Once(key, func() interface{} {
+// Construct the global boot image configs.
+func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
+ return ctx.Config().Once(bootImageConfigKey, func() interface{} {
+
global := dexpreoptGlobalConfig(ctx)
+ targets := dexpreoptTargets(ctx)
+ deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
artModules := global.ArtApexJars
- imageModules := artModules
+ // In coverage builds ART boot class path jars are instrumented and have additional dependencies.
+ if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+ artModules = append(artModules, "jacocoagent")
+ }
+ frameworkModules := android.RemoveListFromList(global.BootJars,
+ concat(artModules, getJarsFromApexJarPairs(global.UpdatableBootJars)))
- var bootLocations []string
+ artSubdir := "apex/com.android.art/javalib"
+ frameworkSubdir := "system/framework"
+ var artLocations, frameworkLocations []string
for _, m := range artModules {
- bootLocations = append(bootLocations,
- filepath.Join("/apex/com.android.art/javalib", stemOf(m)+".jar"))
+ artLocations = append(artLocations, filepath.Join("/"+artSubdir, stemOf(m)+".jar"))
+ }
+ for _, m := range frameworkModules {
+ frameworkLocations = append(frameworkLocations, filepath.Join("/"+frameworkSubdir, stemOf(m)+".jar"))
}
- if !artApexJarsOnly {
- nonFrameworkModules := concat(artModules, getJarsFromApexJarPairs(global.UpdatableBootJars))
- frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules)
- imageModules = concat(imageModules, frameworkModules)
+ // ART config for the primary boot image in the ART apex.
+ // It includes the Core Libraries.
+ artCfg := bootImageConfig{
+ extension: false,
+ name: artBootImageName,
+ stem: "boot",
+ installSubdir: artSubdir,
+ modules: artModules,
+ dexLocations: artLocations,
+ dexLocationsDeps: artLocations,
+ }
- for _, m := range frameworkModules {
- bootLocations = append(bootLocations,
- filepath.Join("/system/framework", stemOf(m)+".jar"))
+ // Framework config for the boot image extension.
+ // It includes framework libraries and depends on the ART config.
+ frameworkCfg := bootImageConfig{
+ extension: true,
+ name: frameworkBootImageName,
+ stem: "boot",
+ installSubdir: frameworkSubdir,
+ modules: frameworkModules,
+ dexLocations: frameworkLocations,
+ dexLocationsDeps: append(artLocations, frameworkLocations...),
+ }
+
+ // Apex config for the boot image used in the JIT-zygote experiment.
+ // It includes both the Core libraries and framework.
+ apexCfg := bootImageConfig{
+ extension: false,
+ name: apexBootImageName,
+ stem: "apex",
+ installSubdir: frameworkSubdir,
+ modules: concat(artModules, frameworkModules),
+ dexLocations: concat(artLocations, frameworkLocations),
+ dexLocationsDeps: concat(artLocations, frameworkLocations),
+ }
+
+ configs := map[string]*bootImageConfig{
+ artBootImageName: &artCfg,
+ frameworkBootImageName: &frameworkCfg,
+ apexBootImageName: &apexCfg,
+ }
+
+ // common to all configs
+ for _, c := range configs {
+ c.targets = targets
+
+ c.dir = deviceDir.Join(ctx, "dex_"+c.name+"jars")
+ c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
+
+ // expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
+ imageName := c.firstModuleNameOrStem() + ".art"
+
+ c.imageLocations = []string{c.dir.Join(ctx, c.installSubdir, imageName).String()}
+
+ // The path to bootclasspath dex files needs to be known at module
+ // GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
+ // Set up known paths for them, the singleton rules will copy them there.
+ // TODO(b/143682396): use module dependencies instead
+ inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
+ for _, m := range c.modules {
+ c.dexPaths = append(c.dexPaths, inputDir.Join(ctx, stemOf(m)+".jar"))
}
- }
+ c.dexPathsDeps = c.dexPaths
- // The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
- // the bootclasspath modules have been compiled. Set up known paths for them, the singleton rules will copy
- // them there.
- // TODO(b/143682396): use module dependencies instead
- var bootDexPaths android.WritablePaths
- for _, m := range imageModules {
- bootDexPaths = append(bootDexPaths,
- android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_"+name+"jars_input", m+".jar"))
- }
+ c.images = make(map[android.ArchType]android.OutputPath)
+ c.imagesDeps = make(map[android.ArchType]android.OutputPaths)
- dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_"+name+"jars")
- symbolsDir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_"+name+"jars_unstripped")
-
- var zip android.WritablePath
- if needZip {
- zip = dir.Join(ctx, stem+".zip")
- }
-
- targets := dexpreoptTargets(ctx)
-
- imageConfig := bootImageConfig{
- name: name,
- stem: stem,
- modules: imageModules,
- dexLocations: bootLocations,
- dexPaths: bootDexPaths,
- dir: dir,
- symbolsDir: symbolsDir,
- targets: targets,
- images: make(map[android.ArchType]android.OutputPath),
- imagesDeps: make(map[android.ArchType]android.Paths),
- zip: zip,
- }
-
- for _, target := range targets {
- imageDir := dir.Join(ctx, "system/framework", target.Arch.ArchType.String())
- imageConfig.images[target.Arch.ArchType] = imageDir.Join(ctx, stem+".art")
-
- imagesDeps := make([]android.Path, 0, len(imageConfig.modules)*3)
- for _, dep := range imageConfig.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex") {
- imagesDeps = append(imagesDeps, dep)
+ for _, target := range targets {
+ arch := target.Arch.ArchType
+ imageDir := c.dir.Join(ctx, c.installSubdir, arch.String())
+ c.images[arch] = imageDir.Join(ctx, imageName)
+ c.imagesDeps[arch] = c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex")
}
- imageConfig.imagesDeps[target.Arch.ArchType] = imagesDeps
+
+ c.zip = c.dir.Join(ctx, c.name+".zip")
}
- return imageConfig
- }).(bootImageConfig)
+ // specific to the framework config
+ frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
+ frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...)
+
+ return configs
+ }).(map[string]*bootImageConfig)
}
-// Default config is the one that goes in the system image. It includes both libcore and framework.
-var defaultBootImageConfigKey = android.NewOnceKey("defaultBootImageConfig")
-
-func defaultBootImageConfig(ctx android.PathContext) bootImageConfig {
- return getBootImageConfig(ctx, defaultBootImageConfigKey, "boot", "boot", true, false)
-}
-
-// Apex config is used for the JIT-zygote experiment. It includes both libcore and framework, but AOT-compiles only libcore.
-var apexBootImageConfigKey = android.NewOnceKey("apexBootImageConfig")
-
-func apexBootImageConfig(ctx android.PathContext) bootImageConfig {
- return getBootImageConfig(ctx, apexBootImageConfigKey, "apex", "apex", false, false)
-}
-
-// ART config is the one used for the ART apex. It includes only libcore.
-var artBootImageConfigKey = android.NewOnceKey("artBootImageConfig")
-
func artBootImageConfig(ctx android.PathContext) bootImageConfig {
- return getBootImageConfig(ctx, artBootImageConfigKey, "art", "boot", false, true)
+ return *genBootImageConfigs(ctx)[artBootImageName]
+}
+
+func defaultBootImageConfig(ctx android.PathContext) bootImageConfig {
+ return *genBootImageConfigs(ctx)[frameworkBootImageName]
+}
+
+func apexBootImageConfig(ctx android.PathContext) bootImageConfig {
+ return *genBootImageConfigs(ctx)[apexBootImageName]
}
func defaultBootclasspath(ctx android.PathContext) []string {
return ctx.Config().OnceStringSlice(defaultBootclasspathKey, func() []string {
global := dexpreoptGlobalConfig(ctx)
image := defaultBootImageConfig(ctx)
+
updatableBootclasspath := make([]string, len(global.UpdatableBootJars))
for i, p := range global.UpdatableBootJars {
updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(p)
}
- bootclasspath := append(copyOf(image.dexLocations), updatableBootclasspath...)
+
+ bootclasspath := append(copyOf(image.dexLocationsDeps), updatableBootclasspath...)
return bootclasspath
})
}
@@ -245,7 +275,7 @@
func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":"))
- ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).dexLocations, ":"))
+ ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).dexLocationsDeps, ":"))
ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":"))
ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules, ":"))
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 96c8416..76cdaea 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -19,6 +19,7 @@
"path/filepath"
"strings"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
@@ -1973,34 +1974,32 @@
return module
}
-func (d *Droidstubs) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder) {
+var DroidStubsSdkMemberType = &droidStubsSdkMemberType{}
+
+type droidStubsSdkMemberType struct {
+}
+
+func (mt *droidStubsSdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+ mctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (mt *droidStubsSdkMemberType) IsInstance(module android.Module) bool {
+ _, ok := module.(*Droidstubs)
+ return ok
+}
+
+func (mt *droidStubsSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+ variants := member.Variants()
+ if len(variants) != 1 {
+ sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
+ }
+ variant := variants[0]
+ d, _ := variant.(*Droidstubs)
stubsSrcJar := d.stubsSrcJar
snapshotRelativeDir := filepath.Join("java", d.Name()+"_stubs_sources")
builder.UnzipToSnapshot(stubsSrcJar, snapshotRelativeDir)
- d.generatePrebuiltStubsSources(builder, snapshotRelativeDir, true)
-
- // This module is for the case when the source tree for the unversioned module
- // doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false
- // so that this module does not eclipse the unversioned module if it exists.
- d.generatePrebuiltStubsSources(builder, snapshotRelativeDir, false)
-}
-
-func (d *Droidstubs) generatePrebuiltStubsSources(builder android.SnapshotBuilder, snapshotRelativeDir string, versioned bool) {
- bp := builder.AndroidBpFile()
- name := d.Name()
- bp.Printfln("prebuilt_stubs_sources {")
- bp.Indent()
- if versioned {
- bp.Printfln("name: %q,", builder.VersionedSdkMemberName(name))
- bp.Printfln("sdk_member_name: %q,", name)
- } else {
- bp.Printfln("name: %q,", name)
- bp.Printfln("prefer: false,")
- }
- bp.Printfln("srcs: [%q],", snapshotRelativeDir)
- bp.Dedent()
- bp.Printfln("}")
- bp.Printfln("")
+ pbm := builder.AddPrebuiltModule(member, "prebuilt_stubs_sources")
+ pbm.AddProperty("srcs", []string{snapshotRelativeDir})
}
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index c0ef444..ad84cde 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -190,7 +190,7 @@
rule.MissingDeps(missingDeps)
rule.Command().
- Tool(pctx.HostBinToolPath(ctx, "hiddenapi")).
+ Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
Text("list").
FlagForEachInput("--boot-dex=", bootDexJars).
FlagWithInputList("--public-stub-classpath=", publicStubPaths, ":").
diff --git a/java/java.go b/java/java.go
index 5cd074a..f58e5ba 100644
--- a/java/java.go
+++ b/java/java.go
@@ -34,7 +34,7 @@
)
func init() {
- android.RegisterModuleType("java_defaults", defaultsFactory)
+ android.RegisterModuleType("java_defaults", DefaultsFactory)
android.RegisterModuleType("java_library", LibraryFactory)
android.RegisterModuleType("java_library_static", LibraryStaticFactory)
@@ -792,8 +792,7 @@
return
}
switch module.(type) {
- case *Library:
- case *AndroidLibrary:
+ case *Library, *AndroidLibrary:
if to, ok := module.(linkTypeContext); ok {
switch tag {
case bootClasspathTag, libTag, staticLibTag:
@@ -1711,23 +1710,47 @@
}
const (
- aidlIncludeDir = "aidl"
- javaStubDir = "java"
- javaStubFileSuffix = ".jar"
+ aidlIncludeDir = "aidl"
+ javaDir = "java"
+ jarFileSuffix = ".jar"
)
-// path to the stub file of a java library. Relative to <sdk_root>/<api_dir>
-func (j *Library) javaStubFilePathFor() string {
- return filepath.Join(javaStubDir, j.Name()+javaStubFileSuffix)
+// path to the jar file of a java library. Relative to <sdk_root>/<api_dir>
+func (j *Library) sdkSnapshotFilePathForJar() string {
+ return filepath.Join(javaDir, j.Name()+jarFileSuffix)
}
-func (j *Library) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder) {
- headerJars := j.HeaderJars()
- if len(headerJars) != 1 {
- panic(fmt.Errorf("there must be only one header jar from %q", j.Name()))
+type librarySdkMemberType struct {
+}
+
+func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+ mctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (mt *librarySdkMemberType) IsInstance(module android.Module) bool {
+ _, ok := module.(*Library)
+ return ok
+}
+
+func (mt *librarySdkMemberType) buildSnapshot(
+ sdkModuleContext android.ModuleContext,
+ builder android.SnapshotBuilder,
+ member android.SdkMember,
+ jarToExportGetter func(j *Library) android.Path) {
+
+ variants := member.Variants()
+ if len(variants) != 1 {
+ sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
+ for _, variant := range variants {
+ sdkModuleContext.ModuleErrorf(" %q", variant)
+ }
}
- snapshotRelativeJavaLibPath := j.javaStubFilePathFor()
- builder.CopyToSnapshot(headerJars[0], snapshotRelativeJavaLibPath)
+ variant := variants[0]
+ j := variant.(*Library)
+
+ exportedJar := jarToExportGetter(j)
+ snapshotRelativeJavaLibPath := j.sdkSnapshotFilePathForJar()
+ builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
for _, dir := range j.AidlIncludeDirs() {
// TODO(jiyong): copy parcelable declarations only
@@ -1737,30 +1760,42 @@
}
}
- j.generateJavaImport(builder, snapshotRelativeJavaLibPath, true)
-
- // This module is for the case when the source tree for the unversioned module
- // doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false
- // so that this module does not eclipse the unversioned module if it exists.
- j.generateJavaImport(builder, snapshotRelativeJavaLibPath, false)
+ module := builder.AddPrebuiltModule(member, "java_import")
+ module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
}
-func (j *Library) generateJavaImport(builder android.SnapshotBuilder, snapshotRelativeJavaLibPath string, versioned bool) {
- bp := builder.AndroidBpFile()
- name := j.Name()
- bp.Printfln("java_import {")
- bp.Indent()
- if versioned {
- bp.Printfln("name: %q,", builder.VersionedSdkMemberName(name))
- bp.Printfln("sdk_member_name: %q,", name)
- } else {
- bp.Printfln("name: %q,", name)
- bp.Printfln("prefer: false,")
- }
- bp.Printfln("jars: [%q],", snapshotRelativeJavaLibPath)
- bp.Dedent()
- bp.Printfln("}")
- bp.Printfln("")
+var HeaderLibrarySdkMemberType = &headerLibrarySdkMemberType{}
+
+type headerLibrarySdkMemberType struct {
+ librarySdkMemberType
+}
+
+func (mt *headerLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+ mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
+ headerJars := j.HeaderJars()
+ if len(headerJars) != 1 {
+ panic(fmt.Errorf("there must be only one header jar from %q", j.Name()))
+ }
+
+ return headerJars[0]
+ })
+}
+
+var ImplLibrarySdkMemberType = &implLibrarySdkMemberType{}
+
+type implLibrarySdkMemberType struct {
+ librarySdkMemberType
+}
+
+func (mt *implLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
+ mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
+ implementationJars := j.ImplementationJars()
+ if len(implementationJars) != 1 {
+ panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+ }
+
+ return implementationJars[0]
+ })
}
// java_library builds and links sources into a `.jar` file for the device, and possibly for the host as well.
@@ -2416,10 +2451,9 @@
return DefaultsFactory()
}
-func DefaultsFactory(props ...interface{}) android.Module {
+func DefaultsFactory() android.Module {
module := &Defaults{}
- module.AddProperties(props...)
module.AddProperties(
&CompilerProperties{},
&CompilerDeviceProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index dc498a4..f4b92e3 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -79,7 +79,7 @@
ctx.RegisterModuleType("java_test", TestFactory)
ctx.RegisterModuleType("java_import", ImportFactory)
ctx.RegisterModuleType("java_import_host", ImportFactoryHost)
- ctx.RegisterModuleType("java_defaults", defaultsFactory)
+ ctx.RegisterModuleType("java_defaults", DefaultsFactory)
ctx.RegisterModuleType("java_system_modules", SystemModulesFactory)
ctx.RegisterModuleType("java_genrule", genRuleFactory)
ctx.RegisterModuleType("java_plugin", PluginFactory)
@@ -288,6 +288,94 @@
}
}
+func TestJavaLinkType(t *testing.T) {
+ testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ static_libs: ["baz"],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["b.java"],
+ }
+
+ java_library {
+ name: "baz",
+ sdk_version: "system_current",
+ srcs: ["c.java"],
+ }
+ `)
+
+ testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ sdk_version: "current",
+ static_libs: ["baz"],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["b.java"],
+ }
+
+ java_library {
+ name: "baz",
+ sdk_version: "system_current",
+ srcs: ["c.java"],
+ }
+ `)
+
+ testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ sdk_version: "system_current",
+ static_libs: ["baz"],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["b.java"],
+ }
+
+ java_library {
+ name: "baz",
+ sdk_version: "system_current",
+ srcs: ["c.java"],
+ }
+ `)
+
+ testJavaError(t, "Adjust sdk_version: property of the source or target module so that target module is built with the same or smaller API set than the source.", `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ libs: ["bar"],
+ sdk_version: "system_current",
+ static_libs: ["baz"],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["b.java"],
+ }
+
+ java_library {
+ name: "baz",
+ srcs: ["c.java"],
+ }
+ `)
+}
+
func TestSimple(t *testing.T) {
ctx, _ := testJava(t, `
java_library {
@@ -1089,7 +1177,7 @@
ctx.ModuleForTests("foo"+sdkDocsSuffix, "android_common")
ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkSystemApiSuffix, "android_common")
ctx.ModuleForTests("foo"+sdkDocsSuffix+sdkTestApiSuffix, "android_common")
- ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_arm64_armv8-a")
+ ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_arm64_armv8-a_core")
ctx.ModuleForTests("foo.api.public.28", "")
ctx.ModuleForTests("foo.api.system.28", "")
ctx.ModuleForTests("foo.api.test.28", "")
diff --git a/python/tests/par_test.py b/python/tests/par_test.py
index 1fafe0f..56a5063 100644
--- a/python/tests/par_test.py
+++ b/python/tests/par_test.py
@@ -44,6 +44,13 @@
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 os.getenv('ARGTEST', False):
+ assert_equal("len(sys.argv)", len(sys.argv), 3)
+ assert_equal("sys.argv[1]", sys.argv[1], "--arg1")
+ assert_equal("sys.argv[2]", sys.argv[2], "arg2")
+else:
+ assert_equal("len(sys.argv)", len(sys.argv), 1)
+
if failed:
sys.exit(1)
diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh
index 1ecdebc..21187ed 100755
--- a/python/tests/runtest.sh
+++ b/python/tests/runtest.sh
@@ -36,8 +36,12 @@
PYTHONHOME=/usr $ANDROID_HOST_OUT/nativetest64/par_test/par_test
PYTHONPATH=/usr $ANDROID_HOST_OUT/nativetest64/par_test/par_test
+ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test/par_test --arg1 arg2
+
PYTHONHOME= PYTHONPATH= $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
PYTHONHOME=/usr $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
PYTHONPATH=/usr $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3
+ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test3/par_test3 --arg1 arg2
+
echo "Passed!"
diff --git a/rust/androidmk.go b/rust/androidmk.go
index edd5c5f..2636d97 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -90,11 +90,7 @@
func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
test.binaryDecorator.AndroidMk(ctx, ret)
ret.Class = "NATIVE_TESTS"
- stem := String(test.baseCompiler.Properties.Stem)
- if stem != "" && !strings.HasSuffix(ctx.Name(), "_"+stem) {
- // Avoid repeated suffix in the module name.
- ret.SubName = "_" + stem
- }
+ ret.SubName = test.getMutatedModuleSubName(ctx.Name())
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
if len(test.Properties.Test_suites) > 0 {
fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
diff --git a/rust/test.go b/rust/test.go
index cb64e8f..b391103 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -69,15 +69,28 @@
return append(test.binaryDecorator.compilerProps(), &test.Properties)
}
+func (test *testDecorator) getMutatedModuleSubName(moduleName string) string {
+ stem := String(test.baseCompiler.Properties.Stem)
+ if stem != "" && !strings.HasSuffix(moduleName, "_"+stem) {
+ // Avoid repeated suffix in the module name.
+ return "_" + stem
+ }
+ return ""
+}
+
func (test *testDecorator) install(ctx ModuleContext, file android.Path) {
name := ctx.ModuleName() // default executable name
- if stem := String(test.baseCompiler.Properties.Stem); stem != "" {
- name = stem
+ if ctx.Device() { // on device, use mutated module name
+ name = name + test.getMutatedModuleSubName(name)
+ } else { // on host, use stem name in relative_install_path
+ if stem := String(test.baseCompiler.Properties.Stem); stem != "" {
+ name = stem
+ }
+ if path := test.baseCompiler.relativeInstallPath(); path != "" {
+ name = path + "/" + name
+ }
}
- if path := test.baseCompiler.relativeInstallPath(); path != "" {
- name = path + "/" + name
- }
- test.testConfig = tradefed.AutoGenRustHostTestConfig(ctx, name,
+ test.testConfig = tradefed.AutoGenRustTestConfig(ctx, name,
test.Properties.Test_config,
test.Properties.Test_config_template,
test.Properties.Test_suites,
diff --git a/rust/testing.go b/rust/testing.go
index 45dbbbd..2067f82 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -185,7 +185,6 @@
ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
// cc mutators
- ctx.BottomUp("image", android.ImageMutator).Parallel()
ctx.BottomUp("link", cc.LinkageMutator).Parallel()
ctx.BottomUp("version", cc.VersionMutator).Parallel()
ctx.BottomUp("begin", cc.BeginMutator).Parallel()
diff --git a/sdk/bp.go b/sdk/bp.go
new file mode 100644
index 0000000..19fb70d
--- /dev/null
+++ b/sdk/bp.go
@@ -0,0 +1,141 @@
+// 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 sdk
+
+import (
+ "fmt"
+
+ "android/soong/android"
+)
+
+type bpPropertySet struct {
+ properties map[string]interface{}
+ order []string
+}
+
+var _ android.BpPropertySet = (*bpPropertySet)(nil)
+
+func (s *bpPropertySet) init() {
+ s.properties = make(map[string]interface{})
+}
+
+func (s *bpPropertySet) AddProperty(name string, value interface{}) {
+ if s.properties[name] != nil {
+ panic("Property %q already exists in property set")
+ }
+
+ s.properties[name] = value
+ s.order = append(s.order, name)
+}
+
+func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
+ set := &bpPropertySet{}
+ set.init()
+ s.AddProperty(name, set)
+ return set
+}
+
+func (s *bpPropertySet) getValue(name string) interface{} {
+ return s.properties[name]
+}
+
+func (s *bpPropertySet) copy() bpPropertySet {
+ propertiesCopy := make(map[string]interface{})
+ for p, v := range s.properties {
+ propertiesCopy[p] = v
+ }
+
+ return bpPropertySet{
+ properties: propertiesCopy,
+ order: append([]string(nil), s.order...),
+ }
+}
+
+func (s *bpPropertySet) setProperty(name string, value interface{}) {
+ if s.properties[name] == nil {
+ s.AddProperty(name, value)
+ } else {
+ s.properties[name] = value
+ }
+}
+
+func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
+ if s.properties[name] != nil {
+ panic("Property %q already exists in property set")
+ }
+
+ // Add the name to the end of the order, to ensure it has necessary capacity
+ // and to handle the case when the position does not exist.
+ s.order = append(s.order, name)
+
+ // Search through the order for the item that matches supplied position. If
+ // found then insert the name of the new property after it.
+ for i, v := range s.order {
+ if v == position {
+ // Copy the items after the one where the new property should be inserted.
+ copy(s.order[i+2:], s.order[i+1:])
+ // Insert the item in the list.
+ s.order[i+1] = name
+ }
+ }
+
+ s.properties[name] = value
+}
+
+type bpModule struct {
+ bpPropertySet
+ moduleType string
+}
+
+var _ android.BpModule = (*bpModule)(nil)
+
+func (m *bpModule) copy() *bpModule {
+ return &bpModule{
+ bpPropertySet: m.bpPropertySet.copy(),
+ moduleType: m.moduleType,
+ }
+}
+
+// A .bp file
+type bpFile struct {
+ modules map[string]*bpModule
+ order []*bpModule
+}
+
+// Add a module.
+//
+// The module must have had its "name" property set to a string value that
+// is unique within this file.
+func (f *bpFile) AddModule(module android.BpModule) {
+ m := module.(*bpModule)
+ if name, ok := m.getValue("name").(string); ok {
+ if f.modules[name] != nil {
+ panic(fmt.Sprintf("Module %q already exists in bp file", name))
+ }
+
+ f.modules[name] = m
+ f.order = append(f.order, m)
+ } else {
+ panic("Module does not have a name property, or it is not a string")
+ }
+}
+
+func (f *bpFile) newModule(moduleType string) *bpModule {
+ module := &bpModule{
+ moduleType: moduleType,
+ }
+ (&module.bpPropertySet).init()
+ return module
+}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
new file mode 100644
index 0000000..7620ec1
--- /dev/null
+++ b/sdk/cc_sdk_test.go
@@ -0,0 +1,340 @@
+// 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 sdk
+
+import (
+ "testing"
+
+ "android/soong/cc"
+)
+
+func testSdkWithCc(t *testing.T, bp string) *testSdkResult {
+ t.Helper()
+
+ fs := map[string][]byte{
+ "Test.cpp": nil,
+ "include/Test.h": nil,
+ "libfoo.so": nil,
+ "aidl/foo/bar/Test.aidl": nil,
+ }
+ return testSdkWithFs(t, bp, fs)
+}
+
+// Contains tests for SDK members provided by the cc package.
+
+func TestSdkIsCompileMultilibBoth(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: ["sdkmember"],
+ }
+
+ cc_library_shared {
+ name: "sdkmember",
+ srcs: ["Test.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ armOutput := result.Module("sdkmember", "android_arm_armv7-a-neon_core_shared").(*cc.Module).OutputFile()
+ arm64Output := result.Module("sdkmember", "android_arm64_armv8-a_core_shared").(*cc.Module).OutputFile()
+
+ var inputs []string
+ buildParams := result.Module("mysdk", "android_common").BuildParamsForTests()
+ for _, bp := range buildParams {
+ if bp.Input != nil {
+ inputs = append(inputs, bp.Input.String())
+ }
+ }
+
+ // ensure that both 32/64 outputs are inputs of the sdk snapshot
+ ensureListContains(t, inputs, armOutput.String())
+ ensureListContains(t, inputs, arm64Output.String())
+}
+
+func TestBasicSdkWithCc(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: ["sdkmember"],
+ }
+
+ sdk_snapshot {
+ name: "mysdk@1",
+ native_shared_libs: ["sdkmember_mysdk_1"],
+ }
+
+ sdk_snapshot {
+ name: "mysdk@2",
+ native_shared_libs: ["sdkmember_mysdk_2"],
+ }
+
+ cc_prebuilt_library_shared {
+ name: "sdkmember",
+ srcs: ["libfoo.so"],
+ prefer: false,
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_prebuilt_library_shared {
+ name: "sdkmember_mysdk_1",
+ sdk_member_name: "sdkmember",
+ srcs: ["libfoo.so"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_prebuilt_library_shared {
+ name: "sdkmember_mysdk_2",
+ sdk_member_name: "sdkmember",
+ srcs: ["libfoo.so"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library_shared {
+ name: "mycpplib",
+ srcs: ["Test.cpp"],
+ shared_libs: ["sdkmember"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ apex {
+ name: "myapex",
+ native_shared_libs: ["mycpplib"],
+ uses_sdks: ["mysdk@1"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
+
+ apex {
+ name: "myapex2",
+ native_shared_libs: ["mycpplib"],
+ uses_sdks: ["mysdk@2"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
+ `)
+
+ sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_core_shared_myapex").Rule("toc").Output
+ sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_core_shared_myapex2").Rule("toc").Output
+
+ cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex")
+ cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex2")
+
+ // Depending on the uses_sdks value, different libs are linked
+ ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String())
+ ensureListContains(t, pathsToStrings(cpplibForMyApex2.Rule("ld").Implicits), sdkMemberV2.String())
+}
+
+func TestSnapshotWithCcShared(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ native_shared_libs: ["mynativelib"],
+ }
+
+ cc_library_shared {
+ name: "mynativelib",
+ srcs: [
+ "Test.cpp",
+ "aidl/foo/bar/Test.aidl",
+ ],
+ export_include_dirs: ["include"],
+ aidl: {
+ export_aidl_headers: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "android_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ export_include_dirs: [
+ "arm64/include/include",
+ "arm64/include_gen/mynativelib",
+ ],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ export_include_dirs: [
+ "arm/include/include",
+ "arm/include_gen/mynativelib",
+ ],
+ },
+ },
+ stl: "none",
+ system_shared_libs: [],
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ arch: {
+ arm64: {
+ srcs: ["arm64/lib/mynativelib.so"],
+ export_include_dirs: [
+ "arm64/include/include",
+ "arm64/include_gen/mynativelib",
+ ],
+ },
+ arm: {
+ srcs: ["arm/lib/mynativelib.so"],
+ export_include_dirs: [
+ "arm/include/include",
+ "arm/include_gen/mynativelib",
+ ],
+ },
+ },
+ stl: "none",
+ system_shared_libs: [],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ native_shared_libs: ["mysdk_mynativelib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativelib/android_arm64_armv8-a_core_shared/mynativelib.so -> arm64/lib/mynativelib.so
+include/Test.h -> arm64/include/include/Test.h
+.intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/Test.h -> arm64/include_gen/mynativelib/aidl/foo/bar/Test.h
+.intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/BnTest.h -> arm64/include_gen/mynativelib/aidl/foo/bar/BnTest.h
+.intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/BpTest.h -> arm64/include_gen/mynativelib/aidl/foo/bar/BpTest.h
+.intermediates/mynativelib/android_arm_armv7-a-neon_core_shared/mynativelib.so -> arm/lib/mynativelib.so
+include/Test.h -> arm/include/include/Test.h
+.intermediates/mynativelib/android_arm_armv7-a-neon_core_shared/gen/aidl/aidl/foo/bar/Test.h -> arm/include_gen/mynativelib/aidl/foo/bar/Test.h
+.intermediates/mynativelib/android_arm_armv7-a-neon_core_shared/gen/aidl/aidl/foo/bar/BnTest.h -> arm/include_gen/mynativelib/aidl/foo/bar/BnTest.h
+.intermediates/mynativelib/android_arm_armv7-a-neon_core_shared/gen/aidl/aidl/foo/bar/BpTest.h -> arm/include_gen/mynativelib/aidl/foo/bar/BpTest.h
+`),
+ )
+}
+
+func TestHostSnapshotWithCcShared(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ device_supported: false,
+ host_supported: true,
+ native_shared_libs: ["mynativelib"],
+ }
+
+ cc_library_shared {
+ name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ srcs: [
+ "Test.cpp",
+ "aidl/foo/bar/Test.aidl",
+ ],
+ export_include_dirs: ["include"],
+ aidl: {
+ export_aidl_headers: true,
+ },
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ arch: {
+ x86_64: {
+ srcs: ["x86_64/lib/mynativelib.so"],
+ export_include_dirs: [
+ "x86_64/include/include",
+ "x86_64/include_gen/mynativelib",
+ ],
+ },
+ x86: {
+ srcs: ["x86/lib/mynativelib.so"],
+ export_include_dirs: [
+ "x86/include/include",
+ "x86/include_gen/mynativelib",
+ ],
+ },
+ },
+ stl: "none",
+ system_shared_libs: [],
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ arch: {
+ x86_64: {
+ srcs: ["x86_64/lib/mynativelib.so"],
+ export_include_dirs: [
+ "x86_64/include/include",
+ "x86_64/include_gen/mynativelib",
+ ],
+ },
+ x86: {
+ srcs: ["x86/lib/mynativelib.so"],
+ export_include_dirs: [
+ "x86/include/include",
+ "x86/include_gen/mynativelib",
+ ],
+ },
+ },
+ stl: "none",
+ system_shared_libs: [],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ device_supported: false,
+ host_supported: true,
+ native_shared_libs: ["mysdk_mynativelib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativelib/linux_glibc_x86_64_shared/mynativelib.so -> x86_64/lib/mynativelib.so
+include/Test.h -> x86_64/include/include/Test.h
+.intermediates/mynativelib/linux_glibc_x86_64_shared/gen/aidl/aidl/foo/bar/Test.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/Test.h
+.intermediates/mynativelib/linux_glibc_x86_64_shared/gen/aidl/aidl/foo/bar/BnTest.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/BnTest.h
+.intermediates/mynativelib/linux_glibc_x86_64_shared/gen/aidl/aidl/foo/bar/BpTest.h -> x86_64/include_gen/mynativelib/aidl/foo/bar/BpTest.h
+.intermediates/mynativelib/linux_glibc_x86_shared/mynativelib.so -> x86/lib/mynativelib.so
+include/Test.h -> x86/include/include/Test.h
+.intermediates/mynativelib/linux_glibc_x86_shared/gen/aidl/aidl/foo/bar/Test.h -> x86/include_gen/mynativelib/aidl/foo/bar/Test.h
+.intermediates/mynativelib/linux_glibc_x86_shared/gen/aidl/aidl/foo/bar/BnTest.h -> x86/include_gen/mynativelib/aidl/foo/bar/BnTest.h
+.intermediates/mynativelib/linux_glibc_x86_shared/gen/aidl/aidl/foo/bar/BpTest.h -> x86/include_gen/mynativelib/aidl/foo/bar/BpTest.h
+`),
+ )
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
new file mode 100644
index 0000000..1aa9184
--- /dev/null
+++ b/sdk/java_sdk_test.go
@@ -0,0 +1,461 @@
+// 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 sdk
+
+import (
+ "testing"
+)
+
+func testSdkWithJava(t *testing.T, bp string) *testSdkResult {
+ t.Helper()
+
+ fs := map[string][]byte{
+ "Test.java": nil,
+ "aidl/foo/bar/Test.aidl": nil,
+ }
+ return testSdkWithFs(t, bp, fs)
+}
+
+// Contains tests for SDK members provided by the java package.
+
+func TestBasicSdkWithJavaLibrary(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ java_header_libs: ["myjavalib"],
+ }
+
+ sdk_snapshot {
+ name: "mysdk@1",
+ java_header_libs: ["sdkmember_mysdk_1"],
+ }
+
+ sdk_snapshot {
+ name: "mysdk@2",
+ java_header_libs: ["sdkmember_mysdk_2"],
+ }
+
+ java_import {
+ name: "sdkmember",
+ prefer: false,
+ host_supported: true,
+ }
+
+ java_import {
+ name: "sdkmember_mysdk_1",
+ sdk_member_name: "sdkmember",
+ host_supported: true,
+ }
+
+ java_import {
+ name: "sdkmember_mysdk_2",
+ sdk_member_name: "sdkmember",
+ host_supported: true,
+ }
+
+ java_library {
+ name: "myjavalib",
+ srcs: ["Test.java"],
+ libs: ["sdkmember"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ host_supported: true,
+ }
+
+ apex {
+ name: "myapex",
+ java_libs: ["myjavalib"],
+ uses_sdks: ["mysdk@1"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
+
+ apex {
+ name: "myapex2",
+ java_libs: ["myjavalib"],
+ uses_sdks: ["mysdk@2"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
+ `)
+
+ sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output
+ sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output
+
+ javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_myapex")
+ javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_myapex2")
+
+ // Depending on the uses_sdks value, different libs are linked
+ ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String())
+ ensureListContains(t, pathsToStrings(javalibForMyApex2.Rule("javac").Implicits), sdkMemberV2.String())
+}
+
+func TestSnapshotWithJavaHeaderLibrary(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ java_header_libs: ["myjavalib"],
+ }
+
+ java_library {
+ name: "myjavalib",
+ srcs: ["Test.java"],
+ aidl: {
+ export_include_dirs: ["aidl"],
+ },
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ host_supported: true,
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "android_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ jars: ["java/myjavalib.jar"],
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ java_header_libs: ["mysdk_myjavalib@current"],
+}
+
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/myjavalib.jar
+aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl
+`),
+ )
+}
+
+func TestHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ device_supported: false,
+ host_supported: true,
+ java_header_libs: ["myjavalib"],
+ }
+
+ java_library {
+ name: "myjavalib",
+ device_supported: false,
+ host_supported: true,
+ srcs: ["Test.java"],
+ aidl: {
+ export_include_dirs: ["aidl"],
+ },
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/myjavalib.jar"],
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ device_supported: false,
+ host_supported: true,
+ java_header_libs: ["mysdk_myjavalib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/myjavalib.jar
+aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl
+`),
+ )
+}
+
+func TestSnapshotWithJavaImplLibrary(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ java_libs: ["myjavalib"],
+ }
+
+ java_library {
+ name: "myjavalib",
+ srcs: ["Test.java"],
+ aidl: {
+ export_include_dirs: ["aidl"],
+ },
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ host_supported: true,
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "android_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ jars: ["java/myjavalib.jar"],
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ java_libs: ["mysdk_myjavalib@current"],
+}
+
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/myjavalib.jar
+aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl
+`),
+ )
+}
+
+func TestHostSnapshotWithJavaImplLibrary(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ device_supported: false,
+ host_supported: true,
+ java_libs: ["myjavalib"],
+ }
+
+ java_library {
+ name: "myjavalib",
+ device_supported: false,
+ host_supported: true,
+ srcs: ["Test.java"],
+ aidl: {
+ export_include_dirs: ["aidl"],
+ },
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/myjavalib.jar"],
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ device_supported: false,
+ host_supported: true,
+ java_libs: ["mysdk_myjavalib@current"],
+}
+`),
+ checkAllCopyRules(`
+.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/myjavalib.jar
+aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl
+`),
+ )
+}
+
+func testSdkWithDroidstubs(t *testing.T, bp string) *testSdkResult {
+ t.Helper()
+
+ fs := map[string][]byte{
+ "foo/bar/Foo.java": nil,
+ "stubs-sources/foo/bar/Foo.java": nil,
+ }
+ return testSdkWithFs(t, bp, fs)
+}
+
+// Note: This test does not verify that a droidstubs can be referenced, either
+// directly or indirectly from an APEX as droidstubs can never be a part of an
+// apex.
+func TestBasicSdkWithDroidstubs(t *testing.T) {
+ testSdkWithDroidstubs(t, `
+ sdk {
+ name: "mysdk",
+ stubs_sources: ["mystub"],
+ }
+ sdk_snapshot {
+ name: "mysdk@10",
+ stubs_sources: ["mystub_mysdk@10"],
+ }
+ prebuilt_stubs_sources {
+ name: "mystub_mysdk@10",
+ sdk_member_name: "mystub",
+ srcs: ["stubs-sources/foo/bar/Foo.java"],
+ }
+ droidstubs {
+ name: "mystub",
+ srcs: ["foo/bar/Foo.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ }
+ java_library {
+ name: "myjavalib",
+ srcs: [":mystub"],
+ sdk_version: "none",
+ system_modules: "none",
+ }
+ `)
+}
+
+func TestSnapshotWithDroidstubs(t *testing.T) {
+ result := testSdkWithDroidstubs(t, `
+ sdk {
+ name: "mysdk",
+ stubs_sources: ["myjavaapistubs"],
+ }
+
+ droidstubs {
+ name: "myjavaapistubs",
+ srcs: ["foo/bar/Foo.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "android_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_stubs_sources {
+ name: "mysdk_myjavaapistubs@current",
+ sdk_member_name: "myjavaapistubs",
+ srcs: ["java/myjavaapistubs_stubs_sources"],
+}
+
+prebuilt_stubs_sources {
+ name: "myjavaapistubs",
+ prefer: false,
+ srcs: ["java/myjavaapistubs_stubs_sources"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ stubs_sources: ["mysdk_myjavaapistubs@current"],
+}
+
+`),
+ checkAllCopyRules(""),
+ checkMergeZip(".intermediates/mysdk/android_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
+ )
+}
+
+func TestHostSnapshotWithDroidstubs(t *testing.T) {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ SkipIfNotLinux(t)
+
+ result := testSdkWithDroidstubs(t, `
+ sdk {
+ name: "mysdk",
+ device_supported: false,
+ host_supported: true,
+ stubs_sources: ["myjavaapistubs"],
+ }
+
+ droidstubs {
+ name: "myjavaapistubs",
+ device_supported: false,
+ host_supported: true,
+ srcs: ["foo/bar/Foo.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "linux_glibc_common", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_stubs_sources {
+ name: "mysdk_myjavaapistubs@current",
+ sdk_member_name: "myjavaapistubs",
+ device_supported: false,
+ host_supported: true,
+ srcs: ["java/myjavaapistubs_stubs_sources"],
+}
+
+prebuilt_stubs_sources {
+ name: "myjavaapistubs",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ srcs: ["java/myjavaapistubs_stubs_sources"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ device_supported: false,
+ host_supported: true,
+ stubs_sources: ["mysdk_myjavaapistubs@current"],
+}
+`),
+ checkAllCopyRules(""),
+ checkMergeZip(".intermediates/mysdk/linux_glibc_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
+ )
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 431ace9..c7e12b9 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -27,14 +27,25 @@
// registered before mutators in this package. See RegisterPostDepsMutators for more details.
_ "android/soong/apex"
"android/soong/cc"
+ "android/soong/java"
)
func init() {
pctx.Import("android/soong/android")
+ pctx.Import("android/soong/java/config")
+
android.RegisterModuleType("sdk", ModuleFactory)
android.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory)
android.PreDepsMutators(RegisterPreDepsMutators)
android.PostDepsMutators(RegisterPostDepsMutators)
+
+ // Populate the dependency tags for each member list property. This needs to
+ // be done here to break an initialization cycle.
+ for _, memberListProperty := range sdkMemberListProperties {
+ memberListProperty.dependencyTag = &sdkMemberDependencyTag{
+ memberListProperty: memberListProperty,
+ }
+ }
}
type sdk struct {
@@ -50,7 +61,12 @@
}
type sdkProperties struct {
- // The list of java libraries in this SDK
+ // The list of java header libraries in this SDK
+ //
+ // This should be used for java libraries that are provided separately at runtime,
+ // e.g. through an APEX.
+ Java_header_libs []string
+ // The list of java implementation libraries in this SDK
Java_libs []string
// The list of native libraries in this SDK
Native_shared_libs []string
@@ -60,6 +76,57 @@
Snapshot bool `blueprint:"mutated"`
}
+type sdkMemberDependencyTag struct {
+ blueprint.BaseDependencyTag
+ memberListProperty *sdkMemberListProperty
+}
+
+// Contains information about the sdk properties that list sdk members, e.g.
+// Java_header_libs.
+type sdkMemberListProperty struct {
+ // the name of the property as used in a .bp file
+ name string
+
+ // getter for the list of member names
+ getter func(properties *sdkProperties) []string
+
+ // the type of member referenced in the list
+ memberType android.SdkMemberType
+
+ // the dependency tag used for items in this list.
+ dependencyTag *sdkMemberDependencyTag
+}
+
+// Information about how to handle each member list property.
+//
+// It is organized first by package and then by name within the package.
+// Packages are in alphabetical order and properties are in alphabetical order
+// within each package.
+var sdkMemberListProperties = []*sdkMemberListProperty{
+ // Members from cc package.
+ {
+ name: "native_shared_libs",
+ getter: func(properties *sdkProperties) []string { return properties.Native_shared_libs },
+ memberType: cc.LibrarySdkMemberType,
+ },
+ // Members from java package.
+ {
+ name: "java_header_libs",
+ getter: func(properties *sdkProperties) []string { return properties.Java_header_libs },
+ memberType: java.HeaderLibrarySdkMemberType,
+ },
+ {
+ name: "java_libs",
+ getter: func(properties *sdkProperties) []string { return properties.Java_libs },
+ memberType: java.ImplLibrarySdkMemberType,
+ },
+ {
+ name: "stubs_sources",
+ getter: func(properties *sdkProperties) []string { return properties.Stubs_sources },
+ memberType: java.DroidStubsSdkMemberType,
+ },
+}
+
// sdk defines an SDK which is a logical group of modules (e.g. native libs, headers, java libs, etc.)
// which Mainline modules like APEX can choose to build with.
func ModuleFactory() android.Module {
@@ -143,10 +210,6 @@
blueprint.BaseDependencyTag
}
-// For dependencies from an SDK module to its members
-// e.g. mysdk -> libfoo and libbar
-var sdkMemberDepTag dependencyTag
-
// For dependencies from an in-development version of an SDK member to frozen versions of the same member
// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12
type sdkMemberVesionedDepTag struct {
@@ -158,22 +221,10 @@
// Step 1: create dependencies from an SDK module to its members.
func memberMutator(mctx android.BottomUpMutatorContext) {
if m, ok := mctx.Module().(*sdk); ok {
- mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Java_libs...)
- mctx.AddVariationDependencies(nil, sdkMemberDepTag, m.properties.Stubs_sources...)
-
- targets := mctx.MultiTargets()
- for _, target := range targets {
- for _, lib := range m.properties.Native_shared_libs {
- name, version := cc.StubsLibNameAndVersion(lib)
- if version == "" {
- version = cc.LatestStubsVersionFor(mctx.Config(), name)
- }
- mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: android.CoreVariation},
- {Mutator: "link", Variation: "shared"},
- {Mutator: "version", Variation: version},
- }...), sdkMemberDepTag, name)
- }
+ for _, memberListProperty := range sdkMemberListProperties {
+ names := memberListProperty.getter(&m.properties)
+ tag := memberListProperty.dependencyTag
+ memberListProperty.memberType.AddDependencies(mctx, tag, names)
}
}
}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 1bbd286..d376e59 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -15,338 +15,24 @@
package sdk
import (
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
"testing"
-
- "android/soong/android"
- "android/soong/apex"
- "android/soong/cc"
- "android/soong/java"
)
-func testSdkContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
- config := android.TestArchConfig(buildDir, nil)
- ctx := android.NewTestArchContext()
-
- // from android package
- ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
- ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
- })
- ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
- ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
- })
-
- // from java package
- ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
- ctx.RegisterModuleType("java_library", java.LibraryFactory)
- ctx.RegisterModuleType("java_import", java.ImportFactory)
- ctx.RegisterModuleType("droidstubs", java.DroidstubsFactory)
- ctx.RegisterModuleType("prebuilt_stubs_sources", java.PrebuiltStubsSourcesFactory)
-
- // from cc package
- ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
- ctx.RegisterModuleType("cc_library_shared", cc.LibrarySharedFactory)
- ctx.RegisterModuleType("cc_object", cc.ObjectFactory)
- ctx.RegisterModuleType("cc_prebuilt_library_shared", cc.PrebuiltSharedLibraryFactory)
- ctx.RegisterModuleType("cc_prebuilt_library_static", cc.PrebuiltStaticLibraryFactory)
- ctx.RegisterModuleType("llndk_library", cc.LlndkLibraryFactory)
- ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
- ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("image", android.ImageMutator).Parallel()
- ctx.BottomUp("link", cc.LinkageMutator).Parallel()
- ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
- ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
- ctx.BottomUp("version", cc.VersionMutator).Parallel()
- ctx.BottomUp("begin", cc.BeginMutator).Parallel()
- })
-
- // from apex package
- ctx.RegisterModuleType("apex", apex.BundleFactory)
- ctx.RegisterModuleType("apex_key", apex.ApexKeyFactory)
- ctx.PostDepsMutators(apex.RegisterPostDepsMutators)
-
- // from this package
- ctx.RegisterModuleType("sdk", ModuleFactory)
- ctx.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory)
- ctx.PreDepsMutators(RegisterPreDepsMutators)
- ctx.PostDepsMutators(RegisterPostDepsMutators)
-
- ctx.Register()
-
- bp = bp + `
- apex_key {
- name: "myapex.key",
- public_key: "myapex.avbpubkey",
- private_key: "myapex.pem",
- }
-
- android_app_certificate {
- name: "myapex.cert",
- certificate: "myapex",
- }
- ` + cc.GatherRequiredDepsForTest(android.Android)
-
- ctx.MockFileSystem(map[string][]byte{
- "Android.bp": []byte(bp),
- "build/make/target/product/security": nil,
- "apex_manifest.json": nil,
- "system/sepolicy/apex/myapex-file_contexts": nil,
- "system/sepolicy/apex/myapex2-file_contexts": nil,
- "myapex.avbpubkey": nil,
- "myapex.pem": nil,
- "myapex.x509.pem": nil,
- "myapex.pk8": nil,
- "Test.java": nil,
- "Test.cpp": nil,
- "include/Test.h": nil,
- "aidl/foo/bar/Test.aidl": nil,
- "libfoo.so": nil,
- "stubs-sources/foo/bar/Foo.java": nil,
- "foo/bar/Foo.java": nil,
- })
-
- return ctx, config
-}
-
-func testSdk(t *testing.T, bp string) (*android.TestContext, android.Config) {
- ctx, config := testSdkContext(t, bp)
- _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
- android.FailIfErrored(t, errs)
- _, errs = ctx.PrepareBuildActions(config)
- android.FailIfErrored(t, errs)
- return ctx, config
-}
-
-func testSdkError(t *testing.T, pattern, bp string) {
- t.Helper()
- ctx, config := testSdkContext(t, bp)
- _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
- if len(errs) > 0 {
- android.FailIfNoMatchingErrors(t, pattern, errs)
- return
- }
- _, errs = ctx.PrepareBuildActions(config)
- if len(errs) > 0 {
- android.FailIfNoMatchingErrors(t, pattern, errs)
- return
- }
-
- t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
-}
-
-func ensureListContains(t *testing.T, result []string, expected string) {
- t.Helper()
- if !android.InList(expected, result) {
- t.Errorf("%q is not found in %v", expected, result)
- }
-}
-
-func pathsToStrings(paths android.Paths) []string {
- ret := []string{}
- for _, p := range paths {
- ret = append(ret, p.String())
- }
- return ret
-}
-
-func TestBasicSdkWithJava(t *testing.T) {
- ctx, _ := testSdk(t, `
- sdk {
- name: "mysdk",
- java_libs: ["sdkmember"],
- }
-
- sdk_snapshot {
- name: "mysdk@1",
- java_libs: ["sdkmember_mysdk_1"],
- }
-
- sdk_snapshot {
- name: "mysdk@2",
- java_libs: ["sdkmember_mysdk_2"],
- }
-
- java_import {
- name: "sdkmember",
- prefer: false,
- host_supported: true,
- }
-
- java_import {
- name: "sdkmember_mysdk_1",
- sdk_member_name: "sdkmember",
- host_supported: true,
- }
-
- java_import {
- name: "sdkmember_mysdk_2",
- sdk_member_name: "sdkmember",
- host_supported: true,
- }
-
- java_library {
- name: "myjavalib",
- srcs: ["Test.java"],
- libs: ["sdkmember"],
- system_modules: "none",
- sdk_version: "none",
- compile_dex: true,
- host_supported: true,
- }
-
- apex {
- name: "myapex",
- java_libs: ["myjavalib"],
- uses_sdks: ["mysdk@1"],
- key: "myapex.key",
- certificate: ":myapex.cert",
- }
-
- apex {
- name: "myapex2",
- java_libs: ["myjavalib"],
- uses_sdks: ["mysdk@2"],
- key: "myapex.key",
- certificate: ":myapex.cert",
- }
- `)
-
- sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output
- sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output
-
- javalibForMyApex := ctx.ModuleForTests("myjavalib", "android_common_myapex")
- javalibForMyApex2 := ctx.ModuleForTests("myjavalib", "android_common_myapex2")
-
- // Depending on the uses_sdks value, different libs are linked
- ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String())
- ensureListContains(t, pathsToStrings(javalibForMyApex2.Rule("javac").Implicits), sdkMemberV2.String())
-}
-
-func TestBasicSdkWithCc(t *testing.T) {
- ctx, _ := testSdk(t, `
- sdk {
- name: "mysdk",
- native_shared_libs: ["sdkmember"],
- }
-
- sdk_snapshot {
- name: "mysdk@1",
- native_shared_libs: ["sdkmember_mysdk_1"],
- }
-
- sdk_snapshot {
- name: "mysdk@2",
- native_shared_libs: ["sdkmember_mysdk_2"],
- }
-
- cc_prebuilt_library_shared {
- name: "sdkmember",
- srcs: ["libfoo.so"],
- prefer: false,
- system_shared_libs: [],
- stl: "none",
- }
-
- cc_prebuilt_library_shared {
- name: "sdkmember_mysdk_1",
- sdk_member_name: "sdkmember",
- srcs: ["libfoo.so"],
- system_shared_libs: [],
- stl: "none",
- }
-
- cc_prebuilt_library_shared {
- name: "sdkmember_mysdk_2",
- sdk_member_name: "sdkmember",
- srcs: ["libfoo.so"],
- system_shared_libs: [],
- stl: "none",
- }
-
- cc_library_shared {
- name: "mycpplib",
- srcs: ["Test.cpp"],
- shared_libs: ["sdkmember"],
- system_shared_libs: [],
- stl: "none",
- }
-
- apex {
- name: "myapex",
- native_shared_libs: ["mycpplib"],
- uses_sdks: ["mysdk@1"],
- key: "myapex.key",
- certificate: ":myapex.cert",
- }
-
- apex {
- name: "myapex2",
- native_shared_libs: ["mycpplib"],
- uses_sdks: ["mysdk@2"],
- key: "myapex.key",
- certificate: ":myapex.cert",
- }
- `)
-
- sdkMemberV1 := ctx.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_core_shared_myapex").Rule("toc").Output
- sdkMemberV2 := ctx.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_core_shared_myapex2").Rule("toc").Output
-
- cpplibForMyApex := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex")
- cpplibForMyApex2 := ctx.ModuleForTests("mycpplib", "android_arm64_armv8-a_core_shared_myapex2")
-
- // Depending on the uses_sdks value, different libs are linked
- ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String())
- ensureListContains(t, pathsToStrings(cpplibForMyApex2.Rule("ld").Implicits), sdkMemberV2.String())
-}
-
-// Note: This test does not verify that a droidstubs can be referenced, either
-// directly or indirectly from an APEX as droidstubs can never be a part of an
-// apex.
-func TestBasicSdkWithDroidstubs(t *testing.T) {
- testSdk(t, `
- sdk {
- name: "mysdk",
- stubs_sources: ["mystub"],
- }
- sdk_snapshot {
- name: "mysdk@10",
- stubs_sources: ["mystub_mysdk@10"],
- }
- prebuilt_stubs_sources {
- name: "mystub_mysdk@10",
- sdk_member_name: "mystub",
- srcs: ["stubs-sources/foo/bar/Foo.java"],
- }
- droidstubs {
- name: "mystub",
- srcs: ["foo/bar/Foo.java"],
- sdk_version: "none",
- system_modules: "none",
- }
- java_library {
- name: "myjavalib",
- srcs: [":mystub"],
- sdk_version: "none",
- system_modules: "none",
- }
- `)
+// Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE.
+func TestMain(m *testing.M) {
+ runTestWithBuildDir(m)
}
func TestDepNotInRequiredSdks(t *testing.T) {
testSdkError(t, `module "myjavalib".*depends on "otherlib".*that isn't part of the required SDKs:.*`, `
sdk {
name: "mysdk",
- java_libs: ["sdkmember"],
+ java_header_libs: ["sdkmember"],
}
sdk_snapshot {
name: "mysdk@1",
- java_libs: ["sdkmember_mysdk_1"],
+ java_header_libs: ["sdkmember_mysdk_1"],
}
java_import {
@@ -394,243 +80,122 @@
`)
}
-func TestSdkIsCompileMultilibBoth(t *testing.T) {
- ctx, _ := testSdk(t, `
+// Ensure that prebuilt modules have the same effective visibility as the source
+// modules.
+func TestSnapshotVisibility(t *testing.T) {
+ packageBp := `
+ package {
+ default_visibility: ["//other/foo"],
+ }
+
sdk {
name: "mysdk",
- native_shared_libs: ["sdkmember"],
- }
-
- cc_library_shared {
- name: "sdkmember",
- srcs: ["Test.cpp"],
- system_shared_libs: [],
- stl: "none",
- }
- `)
-
- armOutput := ctx.ModuleForTests("sdkmember", "android_arm_armv7-a-neon_core_shared").Module().(*cc.Module).OutputFile()
- arm64Output := ctx.ModuleForTests("sdkmember", "android_arm64_armv8-a_core_shared").Module().(*cc.Module).OutputFile()
-
- var inputs []string
- buildParams := ctx.ModuleForTests("mysdk", "android_common").Module().BuildParamsForTests()
- for _, bp := range buildParams {
- if bp.Input != nil {
- inputs = append(inputs, bp.Input.String())
- }
- }
-
- // ensure that both 32/64 outputs are inputs of the sdk snapshot
- ensureListContains(t, inputs, armOutput.String())
- ensureListContains(t, inputs, arm64Output.String())
-}
-
-func TestSnapshot(t *testing.T) {
- ctx, config := testSdk(t, `
- sdk {
- name: "mysdk",
- java_libs: ["myjavalib"],
- native_shared_libs: ["mynativelib"],
- stubs_sources: ["myjavaapistubs"],
+ visibility: [
+ "//other/foo",
+ // This short form will be replaced with //package:__subpackages__ in the
+ // generated sdk_snapshot.
+ ":__subpackages__",
+ ],
+ java_header_libs: [
+ "myjavalib",
+ "mypublicjavalib",
+ "mydefaultedjavalib",
+ ],
}
java_library {
name: "myjavalib",
+ // Uses package default visibility
srcs: ["Test.java"],
- aidl: {
- export_include_dirs: ["aidl"],
- },
- system_modules: "none",
- sdk_version: "none",
- compile_dex: true,
- host_supported: true,
- }
-
- cc_library_shared {
- name: "mynativelib",
- srcs: [
- "Test.cpp",
- "aidl/foo/bar/Test.aidl",
- ],
- export_include_dirs: ["include"],
- aidl: {
- export_aidl_headers: true,
- },
- system_shared_libs: [],
- stl: "none",
- }
-
- droidstubs {
- name: "myjavaapistubs",
- srcs: ["foo/bar/Foo.java"],
system_modules: "none",
sdk_version: "none",
}
- `)
- sdk := ctx.ModuleForTests("mysdk", "android_common").Module().(*sdk)
+ java_library {
+ name: "mypublicjavalib",
+ visibility: ["//visibility:public"],
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
- checkSnapshotAndroidBpContents(t, sdk, `// This is auto-generated. DO NOT EDIT.
+ java_defaults {
+ name: "myjavadefaults",
+ visibility: ["//other/bar"],
+ }
+
+ java_library {
+ name: "mydefaultedjavalib",
+ defaults: ["myjavadefaults"],
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+ `
+
+ result := testSdkWithFs(t, ``,
+ map[string][]byte{
+ "package/Test.java": nil,
+ "package/Android.bp": []byte(packageBp),
+ })
+
+ result.CheckSnapshot("mysdk", "android_common", "package",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
java_import {
name: "mysdk_myjavalib@current",
sdk_member_name: "myjavalib",
+ visibility: ["//other/foo:__pkg__"],
jars: ["java/myjavalib.jar"],
}
java_import {
name: "myjavalib",
prefer: false,
+ visibility: ["//other/foo:__pkg__"],
jars: ["java/myjavalib.jar"],
}
-prebuilt_stubs_sources {
- name: "mysdk_myjavaapistubs@current",
- sdk_member_name: "myjavaapistubs",
- srcs: ["java/myjavaapistubs_stubs_sources"],
+java_import {
+ name: "mysdk_mypublicjavalib@current",
+ sdk_member_name: "mypublicjavalib",
+ visibility: ["//visibility:public"],
+ jars: ["java/mypublicjavalib.jar"],
}
-prebuilt_stubs_sources {
- name: "myjavaapistubs",
+java_import {
+ name: "mypublicjavalib",
prefer: false,
- srcs: ["java/myjavaapistubs_stubs_sources"],
+ visibility: ["//visibility:public"],
+ jars: ["java/mypublicjavalib.jar"],
}
-cc_prebuilt_library_shared {
- name: "mysdk_mynativelib@current",
- sdk_member_name: "mynativelib",
- arch: {
- arm64: {
- srcs: ["arm64/lib/mynativelib.so"],
- export_include_dirs: [
- "arm64/include/include",
- "arm64/include_gen/mynativelib",
- ],
- },
- arm: {
- srcs: ["arm/lib/mynativelib.so"],
- export_include_dirs: [
- "arm/include/include",
- "arm/include_gen/mynativelib",
- ],
- },
- },
- stl: "none",
- system_shared_libs: [],
+java_import {
+ name: "mysdk_mydefaultedjavalib@current",
+ sdk_member_name: "mydefaultedjavalib",
+ visibility: ["//other/bar:__pkg__"],
+ jars: ["java/mydefaultedjavalib.jar"],
}
-cc_prebuilt_library_shared {
- name: "mynativelib",
+java_import {
+ name: "mydefaultedjavalib",
prefer: false,
- arch: {
- arm64: {
- srcs: ["arm64/lib/mynativelib.so"],
- export_include_dirs: [
- "arm64/include/include",
- "arm64/include_gen/mynativelib",
- ],
- },
- arm: {
- srcs: ["arm/lib/mynativelib.so"],
- export_include_dirs: [
- "arm/include/include",
- "arm/include_gen/mynativelib",
- ],
- },
- },
- stl: "none",
- system_shared_libs: [],
+ visibility: ["//other/bar:__pkg__"],
+ jars: ["java/mydefaultedjavalib.jar"],
}
sdk_snapshot {
name: "mysdk@current",
- java_libs: [
+ visibility: [
+ "//other/foo:__pkg__",
+ "//package:__subpackages__",
+ ],
+ java_header_libs: [
"mysdk_myjavalib@current",
- ],
- stubs_sources: [
- "mysdk_myjavaapistubs@current",
- ],
- native_shared_libs: [
- "mysdk_mynativelib@current",
+ "mysdk_mypublicjavalib@current",
+ "mysdk_mydefaultedjavalib@current",
],
}
-
-`)
-
- var copySrcs []string
- var copyDests []string
- buildParams := sdk.BuildParamsForTests()
- var zipBp android.BuildParams
- for _, bp := range buildParams {
- ruleString := bp.Rule.String()
- if ruleString == "android/soong/android.Cp" {
- copySrcs = append(copySrcs, bp.Input.String())
- copyDests = append(copyDests, bp.Output.Rel()) // rooted at the snapshot root
- } else if ruleString == "<local rule>:m.mysdk_android_common.snapshot" {
- zipBp = bp
- }
- }
-
- buildDir := config.BuildDir()
- ensureListContains(t, copySrcs, "aidl/foo/bar/Test.aidl")
- ensureListContains(t, copySrcs, "include/Test.h")
- ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/BnTest.h"))
- ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/BpTest.h"))
- ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/gen/aidl/aidl/foo/bar/Test.h"))
- ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar"))
- ensureListContains(t, copySrcs, filepath.Join(buildDir, ".intermediates/mynativelib/android_arm64_armv8-a_core_shared/mynativelib.so"))
-
- ensureListContains(t, copyDests, "aidl/aidl/foo/bar/Test.aidl")
- ensureListContains(t, copyDests, "arm64/include/include/Test.h")
- ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/BnTest.h")
- ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/BpTest.h")
- ensureListContains(t, copyDests, "arm64/include_gen/mynativelib/aidl/foo/bar/Test.h")
- ensureListContains(t, copyDests, "java/myjavalib.jar")
- ensureListContains(t, copyDests, "arm64/lib/mynativelib.so")
-
- // Ensure that the droidstubs .srcjar as repackaged into a temporary zip file
- // and then merged together with the intermediate snapshot zip.
- snapshotCreationInputs := zipBp.Implicits.Strings()
- ensureListContains(t, snapshotCreationInputs,
- filepath.Join(buildDir, ".intermediates/mysdk/android_common/tmp/java/myjavaapistubs_stubs_sources.zip"))
- ensureListContains(t, snapshotCreationInputs,
- filepath.Join(buildDir, ".intermediates/mysdk/android_common/mysdk-current.unmerged.zip"))
- actual := zipBp.Output.String()
- expected := filepath.Join(buildDir, ".intermediates/mysdk/android_common/mysdk-current.zip")
- if actual != expected {
- t.Errorf("Expected snapshot output to be %q but was %q", expected, actual)
- }
-}
-
-func checkSnapshotAndroidBpContents(t *testing.T, s *sdk, expectedContents string) {
- t.Helper()
- androidBpContents := strings.NewReplacer("\\n", "\n").Replace(s.GetAndroidBpContentsForTests())
- if androidBpContents != expectedContents {
- t.Errorf("Android.bp contents do not match, expected %s, actual %s", expectedContents, androidBpContents)
- }
-}
-
-var buildDir string
-
-func setUp() {
- var err error
- buildDir, err = ioutil.TempDir("", "soong_sdk_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())
+`))
}
diff --git a/sdk/testing.go b/sdk/testing.go
new file mode 100644
index 0000000..bd929a4
--- /dev/null
+++ b/sdk/testing.go
@@ -0,0 +1,406 @@
+// 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 sdk
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/apex"
+ "android/soong/cc"
+ "android/soong/java"
+)
+
+func testSdkContext(bp string, fs map[string][]byte) (*android.TestContext, android.Config) {
+ config := android.TestArchConfig(buildDir, nil)
+ ctx := android.NewTestArchContext()
+
+ // from android package
+ ctx.PreArchMutators(android.RegisterPackageRenamer)
+ ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
+ ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
+
+ ctx.PreArchMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("prebuilts", android.PrebuiltMutator).Parallel()
+ })
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("prebuilt_select", android.PrebuiltSelectModuleMutator).Parallel()
+ ctx.BottomUp("prebuilt_postdeps", android.PrebuiltPostDepsMutator).Parallel()
+ })
+ ctx.RegisterModuleType("package", android.PackageFactory)
+
+ // from java package
+ ctx.RegisterModuleType("android_app_certificate", java.AndroidAppCertificateFactory)
+ ctx.RegisterModuleType("java_defaults", java.DefaultsFactory)
+ ctx.RegisterModuleType("java_library", java.LibraryFactory)
+ ctx.RegisterModuleType("java_import", java.ImportFactory)
+ ctx.RegisterModuleType("droidstubs", java.DroidstubsFactory)
+ ctx.RegisterModuleType("prebuilt_stubs_sources", java.PrebuiltStubsSourcesFactory)
+
+ // from cc package
+ ctx.RegisterModuleType("cc_library", cc.LibraryFactory)
+ ctx.RegisterModuleType("cc_library_shared", cc.LibrarySharedFactory)
+ ctx.RegisterModuleType("cc_object", cc.ObjectFactory)
+ ctx.RegisterModuleType("cc_prebuilt_library_shared", cc.PrebuiltSharedLibraryFactory)
+ ctx.RegisterModuleType("cc_prebuilt_library_static", cc.PrebuiltStaticLibraryFactory)
+ ctx.RegisterModuleType("llndk_library", cc.LlndkLibraryFactory)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+ ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
+ ctx.BottomUp("test_per_src", cc.TestPerSrcMutator).Parallel()
+ ctx.BottomUp("version", cc.VersionMutator).Parallel()
+ ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+ })
+
+ // from apex package
+ ctx.RegisterModuleType("apex", apex.BundleFactory)
+ ctx.RegisterModuleType("apex_key", apex.ApexKeyFactory)
+ ctx.PostDepsMutators(apex.RegisterPostDepsMutators)
+
+ // from this package
+ ctx.RegisterModuleType("sdk", ModuleFactory)
+ ctx.RegisterModuleType("sdk_snapshot", SnapshotModuleFactory)
+ ctx.PreDepsMutators(RegisterPreDepsMutators)
+ ctx.PostDepsMutators(RegisterPostDepsMutators)
+
+ ctx.Register()
+
+ bp = bp + `
+ apex_key {
+ name: "myapex.key",
+ public_key: "myapex.avbpubkey",
+ private_key: "myapex.pem",
+ }
+
+ android_app_certificate {
+ name: "myapex.cert",
+ certificate: "myapex",
+ }
+ ` + cc.GatherRequiredDepsForTest(android.Android)
+
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ "build/make/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "system/sepolicy/apex/myapex-file_contexts": nil,
+ "system/sepolicy/apex/myapex2-file_contexts": nil,
+ "myapex.avbpubkey": nil,
+ "myapex.pem": nil,
+ "myapex.x509.pem": nil,
+ "myapex.pk8": nil,
+ }
+
+ for k, v := range fs {
+ mockFS[k] = v
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ return ctx, config
+}
+
+func testSdkWithFs(t *testing.T, bp string, fs map[string][]byte) *testSdkResult {
+ t.Helper()
+ ctx, config := testSdkContext(bp, fs)
+ _, errs := ctx.ParseBlueprintsFiles(".")
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+ return &testSdkResult{
+ TestHelper: TestHelper{t: t},
+ ctx: ctx,
+ config: config,
+ }
+}
+
+func testSdkError(t *testing.T, pattern, bp string) {
+ t.Helper()
+ ctx, config := testSdkContext(bp, nil)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+ _, errs = ctx.PrepareBuildActions(config)
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
+func ensureListContains(t *testing.T, result []string, expected string) {
+ t.Helper()
+ if !android.InList(expected, result) {
+ t.Errorf("%q is not found in %v", expected, result)
+ }
+}
+
+func pathsToStrings(paths android.Paths) []string {
+ var ret []string
+ for _, p := range paths {
+ ret = append(ret, p.String())
+ }
+ return ret
+}
+
+// Provides general test support.
+type TestHelper struct {
+ t *testing.T
+}
+
+func (h *TestHelper) AssertStringEquals(message string, expected string, actual string) {
+ h.t.Helper()
+ if actual != expected {
+ h.t.Errorf("%s: expected %s, actual %s", message, expected, actual)
+ }
+}
+
+func (h *TestHelper) AssertTrimmedStringEquals(message string, expected string, actual string) {
+ h.t.Helper()
+ h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
+}
+
+// Encapsulates result of processing an SDK definition. Provides support for
+// checking the state of the build structures.
+type testSdkResult struct {
+ TestHelper
+ ctx *android.TestContext
+ config android.Config
+}
+
+// Analyse the sdk build rules to extract information about what it is doing.
+
+// e.g. find the src/dest pairs from each cp command, the various zip files
+// generated, etc.
+func (r *testSdkResult) getSdkSnapshotBuildInfo(sdk *sdk) *snapshotBuildInfo {
+ androidBpContents := strings.NewReplacer("\\n", "\n").Replace(sdk.GetAndroidBpContentsForTests())
+
+ info := &snapshotBuildInfo{
+ r: r,
+ androidBpContents: androidBpContents,
+ }
+
+ buildParams := sdk.BuildParamsForTests()
+ copyRules := &strings.Builder{}
+ for _, bp := range buildParams {
+ switch bp.Rule.String() {
+ case android.Cp.String():
+ // Get source relative to build directory.
+ src := r.pathRelativeToBuildDir(bp.Input)
+ // Get destination relative to the snapshot root
+ dest := bp.Output.Rel()
+ _, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
+ info.snapshotContents = append(info.snapshotContents, dest)
+
+ case repackageZip.String():
+ // Add the destdir to the snapshot contents as that is effectively where
+ // the content of the repackaged zip is copied.
+ dest := bp.Args["destdir"]
+ info.snapshotContents = append(info.snapshotContents, dest)
+
+ case zipFiles.String():
+ // This could be an intermediate zip file and not the actual output zip.
+ // In that case this will be overridden when the rule to merge the zips
+ // is processed.
+ info.outputZip = r.pathRelativeToBuildDir(bp.Output)
+
+ case mergeZips.String():
+ // Copy the current outputZip to the intermediateZip.
+ info.intermediateZip = info.outputZip
+ mergeInput := r.pathRelativeToBuildDir(bp.Input)
+ if info.intermediateZip != mergeInput {
+ r.t.Errorf("Expected intermediate zip %s to be an input to merge zips but found %s instead",
+ info.intermediateZip, mergeInput)
+ }
+
+ // Override output zip (which was actually the intermediate zip file) with the actual
+ // output zip.
+ info.outputZip = r.pathRelativeToBuildDir(bp.Output)
+
+ // Save the zips to be merged into the intermediate zip.
+ info.mergeZips = r.pathsRelativeToBuildDir(bp.Inputs)
+ }
+ }
+
+ info.copyRules = copyRules.String()
+
+ return info
+}
+
+func (r *testSdkResult) Module(name string, variant string) android.Module {
+ return r.ctx.ModuleForTests(name, variant).Module()
+}
+
+func (r *testSdkResult) ModuleForTests(name string, variant string) android.TestingModule {
+ return r.ctx.ModuleForTests(name, variant)
+}
+
+func (r *testSdkResult) pathRelativeToBuildDir(path android.Path) string {
+ buildDir := filepath.Clean(r.config.BuildDir()) + "/"
+ return strings.TrimPrefix(filepath.Clean(path.String()), buildDir)
+}
+
+func (r *testSdkResult) pathsRelativeToBuildDir(paths android.Paths) []string {
+ var result []string
+ for _, path := range paths {
+ result = append(result, r.pathRelativeToBuildDir(path))
+ }
+ return result
+}
+
+// Check the snapshot build rules.
+//
+// Takes a list of functions which check different facets of the snapshot build rules.
+// Allows each test to customize what is checked without duplicating lots of code
+// or proliferating check methods of different flavors.
+func (r *testSdkResult) CheckSnapshot(name string, variant string, dir string, checkers ...snapshotBuildInfoChecker) {
+ r.t.Helper()
+
+ sdk := r.Module(name, variant).(*sdk)
+
+ snapshotBuildInfo := r.getSdkSnapshotBuildInfo(sdk)
+
+ // Check state of the snapshot build.
+ for _, checker := range checkers {
+ checker(snapshotBuildInfo)
+ }
+
+ // Make sure that the generated zip file is in the correct place.
+ actual := snapshotBuildInfo.outputZip
+ if dir != "" {
+ dir = filepath.Clean(dir) + "/"
+ }
+ r.AssertStringEquals("Snapshot zip file in wrong place",
+ fmt.Sprintf(".intermediates/%s%s/%s/%s-current.zip", dir, name, variant, name), actual)
+
+ // Populate a mock filesystem with the files that would have been copied by
+ // the rules.
+ fs := make(map[string][]byte)
+ for _, dest := range snapshotBuildInfo.snapshotContents {
+ fs[dest] = nil
+ }
+
+ // Process the generated bp file to make sure it is valid.
+ testSdkWithFs(r.t, snapshotBuildInfo.androidBpContents, fs)
+}
+
+type snapshotBuildInfoChecker func(info *snapshotBuildInfo)
+
+// Check that the snapshot's generated Android.bp is correct.
+//
+// Both the expected and actual string are both trimmed before comparing.
+func checkAndroidBpContents(expected string) snapshotBuildInfoChecker {
+ return func(info *snapshotBuildInfo) {
+ info.r.t.Helper()
+ info.r.AssertTrimmedStringEquals("Android.bp contents do not match", expected, info.androidBpContents)
+ }
+}
+
+// Check that the snapshot's copy rules are correct.
+//
+// The copy rules are formatted as <src> -> <dest>, one per line and then compared
+// to the supplied expected string. Both the expected and actual string are trimmed
+// before comparing.
+func checkAllCopyRules(expected string) snapshotBuildInfoChecker {
+ return func(info *snapshotBuildInfo) {
+ info.r.t.Helper()
+ info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.copyRules)
+ }
+}
+
+// Check that the specified path is in the list of zips to merge with the intermediate zip.
+func checkMergeZip(expected string) snapshotBuildInfoChecker {
+ return func(info *snapshotBuildInfo) {
+ info.r.t.Helper()
+ if info.intermediateZip == "" {
+ info.r.t.Errorf("No intermediate zip file was created")
+ }
+ ensureListContains(info.r.t, info.mergeZips, expected)
+ }
+}
+
+// Encapsulates information about the snapshot build structure in order to insulate tests from
+// knowing too much about internal structures.
+//
+// All source/input paths are relative either the build directory. All dest/output paths are
+// relative to the snapshot root directory.
+type snapshotBuildInfo struct {
+ r *testSdkResult
+
+ // The contents of the generated Android.bp file
+ androidBpContents string
+
+ // The paths, relative to the snapshot root, of all files and directories copied into the
+ // snapshot.
+ snapshotContents []string
+
+ // A formatted representation of the src/dest pairs, one pair per line, of the format
+ // src -> dest
+ copyRules string
+
+ // The path to the intermediate zip, which is a zip created from the source files copied
+ // into the snapshot directory and which will be merged with other zips to form the final output.
+ // Is am empty string if there is no intermediate zip because there are no zips to merge in.
+ intermediateZip string
+
+ // The paths to the zips to merge into the output zip, does not include the intermediate
+ // zip.
+ mergeZips []string
+
+ // The final output zip.
+ outputZip string
+}
+
+var buildDir string
+
+func setUp() {
+ var err error
+ buildDir, err = ioutil.TempDir("", "soong_sdk_test")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func tearDown() {
+ _ = os.RemoveAll(buildDir)
+}
+
+func runTestWithBuildDir(m *testing.M) {
+ run := func() int {
+ setUp()
+ defer tearDown()
+
+ return m.Run()
+ }
+
+ os.Exit(run())
+}
+
+func SkipIfNotLinux(t *testing.T) {
+ t.Helper()
+ if android.BuildOs != android.Linux {
+ t.Skipf("Skipping as sdk snapshot generation is only supported on %s not %s", android.Linux, android.BuildOs)
+ }
+}
diff --git a/sdk/update.go b/sdk/update.go
index 000d200..7fad5c7 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -16,46 +16,78 @@
import (
"fmt"
- "path/filepath"
+ "reflect"
"strings"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
- "android/soong/cc"
- "android/soong/java"
)
var pctx = android.NewPackageContext("android/soong/sdk")
-// generatedFile abstracts operations for writing contents into a file and emit a build rule
-// for the file.
-type generatedFile struct {
- path android.OutputPath
+var (
+ repackageZip = pctx.AndroidStaticRule("SnapshotRepackageZip",
+ blueprint.RuleParams{
+ Command: `${config.Zip2ZipCmd} -i $in -o $out "**/*:$destdir"`,
+ CommandDeps: []string{
+ "${config.Zip2ZipCmd}",
+ },
+ },
+ "destdir")
+
+ zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles",
+ blueprint.RuleParams{
+ Command: `${config.SoongZipCmd} -C $basedir -l $out.rsp -o $out`,
+ CommandDeps: []string{
+ "${config.SoongZipCmd}",
+ },
+ Rspfile: "$out.rsp",
+ RspfileContent: "$in",
+ },
+ "basedir")
+
+ mergeZips = pctx.AndroidStaticRule("SnapshotMergeZips",
+ blueprint.RuleParams{
+ Command: `${config.MergeZipsCmd} $out $in`,
+ CommandDeps: []string{
+ "${config.MergeZipsCmd}",
+ },
+ })
+)
+
+type generatedContents struct {
content strings.Builder
indentLevel int
}
+// generatedFile abstracts operations for writing contents into a file and emit a build rule
+// for the file.
+type generatedFile struct {
+ generatedContents
+ path android.OutputPath
+}
+
func newGeneratedFile(ctx android.ModuleContext, path ...string) *generatedFile {
return &generatedFile{
- path: android.PathForModuleOut(ctx, path...).OutputPath,
- indentLevel: 0,
+ path: android.PathForModuleOut(ctx, path...).OutputPath,
}
}
-func (gf *generatedFile) Indent() {
- gf.indentLevel++
+func (gc *generatedContents) Indent() {
+ gc.indentLevel++
}
-func (gf *generatedFile) Dedent() {
- gf.indentLevel--
+func (gc *generatedContents) Dedent() {
+ gc.indentLevel--
}
-func (gf *generatedFile) Printfln(format string, args ...interface{}) {
+func (gc *generatedContents) Printfln(format string, args ...interface{}) {
// ninja consumes newline characters in rspfile_content. Prevent it by
// escaping the backslash in the newline character. The extra backslash
// is removed when the rspfile is written to the actual script file
- fmt.Fprintf(&(gf.content), strings.Repeat(" ", gf.indentLevel)+format+"\\n", args...)
+ fmt.Fprintf(&(gc.content), strings.Repeat(" ", gc.indentLevel)+format+"\\n", args...)
}
func (gf *generatedFile) build(pctx android.PackageContext, ctx android.BuilderContext, implicits android.Paths) {
@@ -70,105 +102,46 @@
rb.Build(pctx, ctx, gf.path.Base(), "Build "+gf.path.Base())
}
-func (s *sdk) javaLibs(ctx android.ModuleContext) []android.SdkAware {
- result := []android.SdkAware{}
+// Collect all the members.
+//
+// The members are first grouped by type and then grouped by name. The order of
+// the types is the order they are referenced in sdkMemberListProperties. The
+// names are in order in which the dependencies were added.
+func collectMembers(ctx android.ModuleContext) []*sdkMember {
+ byType := make(map[android.SdkMemberType][]*sdkMember)
+ byName := make(map[string]*sdkMember)
+
ctx.VisitDirectDeps(func(m android.Module) {
- if j, ok := m.(*java.Library); ok {
- result = append(result, j)
- }
- })
- return result
-}
+ tag := ctx.OtherModuleDependencyTag(m)
+ if memberTag, ok := tag.(*sdkMemberDependencyTag); ok {
+ memberListProperty := memberTag.memberListProperty
+ memberType := memberListProperty.memberType
-func (s *sdk) stubsSources(ctx android.ModuleContext) []android.SdkAware {
- result := []android.SdkAware{}
- ctx.VisitDirectDeps(func(m android.Module) {
- if j, ok := m.(*java.Droidstubs); ok {
- result = append(result, j)
- }
- })
- return result
-}
-
-// archSpecificNativeLibInfo represents an arch-specific variant of a native lib
-type archSpecificNativeLibInfo struct {
- name string
- archType string
- exportedIncludeDirs android.Paths
- exportedSystemIncludeDirs android.Paths
- exportedFlags []string
- exportedDeps android.Paths
- outputFile android.Path
-}
-
-func (lib *archSpecificNativeLibInfo) signature() string {
- return fmt.Sprintf("%v %v %v %v",
- lib.name,
- lib.exportedIncludeDirs.Strings(),
- lib.exportedSystemIncludeDirs.Strings(),
- lib.exportedFlags)
-}
-
-// nativeLibInfo represents a collection of arch-specific modules having the same name
-type nativeLibInfo struct {
- name string
- archVariants []archSpecificNativeLibInfo
- // hasArchSpecificFlags is set to true if modules for each architecture all have the same
- // include dirs, flags, etc, in which case only those of the first arch is selected.
- hasArchSpecificFlags bool
-}
-
-// nativeMemberInfos collects all cc.Modules that are member of an SDK.
-func (s *sdk) nativeMemberInfos(ctx android.ModuleContext) []*nativeLibInfo {
- infoMap := make(map[string]*nativeLibInfo)
-
- // Collect cc.Modules
- ctx.VisitDirectDeps(func(m android.Module) {
- ccModule, ok := m.(*cc.Module)
- if !ok {
- return
- }
- depName := ctx.OtherModuleName(m)
-
- if _, ok := infoMap[depName]; !ok {
- infoMap[depName] = &nativeLibInfo{name: depName}
- }
-
- info := infoMap[depName]
- info.archVariants = append(info.archVariants, archSpecificNativeLibInfo{
- name: ccModule.BaseModuleName(),
- archType: ccModule.Target().Arch.ArchType.String(),
- exportedIncludeDirs: ccModule.ExportedIncludeDirs(),
- exportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
- exportedFlags: ccModule.ExportedFlags(),
- exportedDeps: ccModule.ExportedDeps(),
- outputFile: ccModule.OutputFile().Path(),
- })
- })
-
- // Determine if include dirs and flags for each module are different across arch-specific
- // modules or not. And set hasArchSpecificFlags accordingly
- for _, info := range infoMap {
- // by default, include paths and flags are assumed to be the same across arches
- info.hasArchSpecificFlags = false
- oldSignature := ""
- for _, av := range info.archVariants {
- newSignature := av.signature()
- if oldSignature == "" {
- oldSignature = newSignature
+ // Make sure that the resolved module is allowed in the member list property.
+ if !memberType.IsInstance(m) {
+ ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(m), memberListProperty.name)
}
- if oldSignature != newSignature {
- info.hasArchSpecificFlags = true
- break
+
+ name := ctx.OtherModuleName(m)
+
+ member := byName[name]
+ if member == nil {
+ member = &sdkMember{memberType: memberType, name: name}
+ byName[name] = member
+ byType[memberType] = append(byType[memberType], member)
}
+
+ member.variants = append(member.variants, m.(android.SdkAware))
}
+ })
+
+ var members []*sdkMember
+ for _, memberListProperty := range sdkMemberListProperties {
+ membersOfType := byType[memberListProperty.memberType]
+ members = append(members, membersOfType...)
}
- var list []*nativeLibInfo
- for _, v := range infoMap {
- list = append(list, v)
- }
- return list
+ return members
}
// SDK directory structure
@@ -189,44 +162,6 @@
// <arch>/lib/
// libFoo.so : a stub library
-const (
- nativeIncludeDir = "include"
- nativeGeneratedIncludeDir = "include_gen"
- nativeStubDir = "lib"
- nativeStubFileSuffix = ".so"
-)
-
-// path to the stub file of a native shared library. Relative to <sdk_root>/<api_dir>
-func nativeStubFilePathFor(lib archSpecificNativeLibInfo) string {
- return filepath.Join(lib.archType,
- nativeStubDir, lib.name+nativeStubFileSuffix)
-}
-
-// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
-func nativeIncludeDirPathsFor(ctx android.ModuleContext, lib archSpecificNativeLibInfo,
- systemInclude bool, archSpecific bool) []string {
- var result []string
- var includeDirs []android.Path
- if !systemInclude {
- includeDirs = lib.exportedIncludeDirs
- } else {
- includeDirs = lib.exportedSystemIncludeDirs
- }
- for _, dir := range includeDirs {
- var path string
- if _, gen := dir.(android.WritablePath); gen {
- path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
- } else {
- path = filepath.Join(nativeIncludeDir, dir.String())
- }
- if archSpecific {
- path = filepath.Join(lib.archType, path)
- }
- result = append(result, path)
- }
- return result
-}
-
// A name that uniquely identifies a prebuilt SDK member for a version of SDK snapshot
// This isn't visible to users, so could be changed in future.
func versionedSdkMemberName(ctx android.ModuleContext, memberName string, version string) string {
@@ -239,71 +174,62 @@
snapshotDir := android.PathForModuleOut(ctx, "snapshot")
bp := newGeneratedFile(ctx, "snapshot", "Android.bp")
- bp.Printfln("// This is auto-generated. DO NOT EDIT.")
- bp.Printfln("")
+
+ bpFile := &bpFile{
+ modules: make(map[string]*bpModule),
+ }
builder := &snapshotBuilder{
- ctx: ctx,
- version: "current",
- snapshotDir: snapshotDir.OutputPath,
- filesToZip: []android.Path{bp.path},
- androidBpFile: bp,
+ ctx: ctx,
+ sdk: s,
+ version: "current",
+ snapshotDir: snapshotDir.OutputPath,
+ filesToZip: []android.Path{bp.path},
+ bpFile: bpFile,
+ prebuiltModules: make(map[string]*bpModule),
}
s.builderForTests = builder
- // copy exported AIDL files and stub jar files
- javaLibs := s.javaLibs(ctx)
- for _, m := range javaLibs {
- m.BuildSnapshot(ctx, builder)
+ for _, member := range collectMembers(ctx) {
+ member.memberType.BuildSnapshot(ctx, builder, member)
}
- // copy stubs sources
- stubsSources := s.stubsSources(ctx)
- for _, m := range stubsSources {
- m.BuildSnapshot(ctx, builder)
+ for _, unversioned := range builder.prebuiltOrder {
+ // Copy the unversioned module so it can be modified to make it versioned.
+ versioned := unversioned.copy()
+ name := versioned.properties["name"].(string)
+ versioned.setProperty("name", builder.versionedSdkMemberName(name))
+ versioned.insertAfter("name", "sdk_member_name", name)
+ bpFile.AddModule(versioned)
+
+ // Set prefer: false - this is not strictly required as that is the default.
+ unversioned.insertAfter("name", "prefer", false)
+ bpFile.AddModule(unversioned)
}
- // copy exported header files and stub *.so files
- nativeLibInfos := s.nativeMemberInfos(ctx)
- for _, info := range nativeLibInfos {
- buildSharedNativeLibSnapshot(ctx, info, builder)
+ // Create the snapshot module.
+ snapshotName := ctx.ModuleName() + string(android.SdkVersionSeparator) + builder.version
+ snapshotModule := bpFile.newModule("sdk_snapshot")
+ snapshotModule.AddProperty("name", snapshotName)
+
+ // Make sure that the snapshot has the same visibility as the sdk.
+ visibility := android.EffectiveVisibilityRules(ctx, s)
+ if len(visibility) != 0 {
+ snapshotModule.AddProperty("visibility", visibility)
}
+ addHostDeviceSupportedProperties(&s.ModuleBase, snapshotModule)
+ for _, memberListProperty := range sdkMemberListProperties {
+ names := memberListProperty.getter(&s.properties)
+ if len(names) > 0 {
+ snapshotModule.AddProperty(memberListProperty.name, builder.versionedSdkMemberNames(names))
+ }
+ }
+ bpFile.AddModule(snapshotModule)
+
// generate Android.bp
-
- bp.Printfln("sdk_snapshot {")
- bp.Indent()
- bp.Printfln("name: %q,", ctx.ModuleName()+string(android.SdkVersionSeparator)+builder.version)
- if len(s.properties.Java_libs) > 0 {
- bp.Printfln("java_libs: [")
- bp.Indent()
- for _, m := range s.properties.Java_libs {
- bp.Printfln("%q,", builder.VersionedSdkMemberName(m))
- }
- bp.Dedent()
- bp.Printfln("],") // java_libs
- }
- if len(s.properties.Stubs_sources) > 0 {
- bp.Printfln("stubs_sources: [")
- bp.Indent()
- for _, m := range s.properties.Stubs_sources {
- bp.Printfln("%q,", builder.VersionedSdkMemberName(m))
- }
- bp.Dedent()
- bp.Printfln("],") // stubs_sources
- }
- if len(s.properties.Native_shared_libs) > 0 {
- bp.Printfln("native_shared_libs: [")
- bp.Indent()
- for _, m := range s.properties.Native_shared_libs {
- bp.Printfln("%q,", builder.VersionedSdkMemberName(m))
- }
- bp.Dedent()
- bp.Printfln("],") // native_shared_libs
- }
- bp.Dedent()
- bp.Printfln("}") // sdk_snapshot
- bp.Printfln("")
+ bp = newGeneratedFile(ctx, "snapshot", "Android.bp")
+ generateBpContents(&bp.generatedContents, bpFile)
bp.build(pctx, ctx, nil)
@@ -311,176 +237,111 @@
// zip them all
outputZipFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.zip").OutputPath
- outputRuleName := "snapshot"
outputDesc := "Building snapshot for " + ctx.ModuleName()
// If there are no zips to merge then generate the output zip directly.
// Otherwise, generate an intermediate zip file into which other zips can be
// merged.
var zipFile android.OutputPath
- var ruleName string
var desc string
if len(builder.zipsToMerge) == 0 {
zipFile = outputZipFile
- ruleName = outputRuleName
desc = outputDesc
} else {
zipFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"-current.unmerged.zip").OutputPath
- ruleName = "intermediate snapshot"
desc = "Building intermediate snapshot for " + ctx.ModuleName()
}
- rb := android.NewRuleBuilder()
- rb.Command().
- BuiltTool(ctx, "soong_zip").
- FlagWithArg("-C ", builder.snapshotDir.String()).
- FlagWithRspFileInputList("-l ", filesToZip).
- FlagWithOutput("-o ", zipFile)
- rb.Build(pctx, ctx, ruleName, desc)
+ ctx.Build(pctx, android.BuildParams{
+ Description: desc,
+ Rule: zipFiles,
+ Inputs: filesToZip,
+ Output: zipFile,
+ Args: map[string]string{
+ "basedir": builder.snapshotDir.String(),
+ },
+ })
if len(builder.zipsToMerge) != 0 {
- rb := android.NewRuleBuilder()
- rb.Command().
- BuiltTool(ctx, "merge_zips").
- Output(outputZipFile).
- Input(zipFile).
- Inputs(builder.zipsToMerge)
- rb.Build(pctx, ctx, outputRuleName, outputDesc)
+ ctx.Build(pctx, android.BuildParams{
+ Description: outputDesc,
+ Rule: mergeZips,
+ Input: zipFile,
+ Inputs: builder.zipsToMerge,
+ Output: outputZipFile,
+ })
}
return outputZipFile
}
+func generateBpContents(contents *generatedContents, bpFile *bpFile) {
+ contents.Printfln("// This is auto-generated. DO NOT EDIT.")
+ for _, bpModule := range bpFile.order {
+ contents.Printfln("")
+ contents.Printfln("%s {", bpModule.moduleType)
+ outputPropertySet(contents, &bpModule.bpPropertySet)
+ contents.Printfln("}")
+ }
+}
+
+func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
+ contents.Indent()
+ for _, name := range set.order {
+ value := set.properties[name]
+
+ reflectedValue := reflect.ValueOf(value)
+ t := reflectedValue.Type()
+
+ kind := t.Kind()
+ switch kind {
+ case reflect.Slice:
+ length := reflectedValue.Len()
+ if length > 1 {
+ contents.Printfln("%s: [", name)
+ contents.Indent()
+ for i := 0; i < length; i = i + 1 {
+ contents.Printfln("%q,", reflectedValue.Index(i).Interface())
+ }
+ contents.Dedent()
+ contents.Printfln("],")
+ } else if length == 0 {
+ contents.Printfln("%s: [],", name)
+ } else {
+ contents.Printfln("%s: [%q],", name, reflectedValue.Index(0).Interface())
+ }
+ case reflect.Bool:
+ contents.Printfln("%s: %t,", name, reflectedValue.Bool())
+
+ case reflect.Ptr:
+ contents.Printfln("%s: {", name)
+ outputPropertySet(contents, reflectedValue.Interface().(*bpPropertySet))
+ contents.Printfln("},")
+
+ default:
+ contents.Printfln("%s: %q,", name, value)
+ }
+ }
+ contents.Dedent()
+}
+
func (s *sdk) GetAndroidBpContentsForTests() string {
- return s.builderForTests.androidBpFile.content.String()
-}
-
-func buildSharedNativeLibSnapshot(ctx android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder) {
- // a function for emitting include dirs
- printExportedDirCopyCommandsForNativeLibs := func(lib archSpecificNativeLibInfo) {
- includeDirs := lib.exportedIncludeDirs
- includeDirs = append(includeDirs, lib.exportedSystemIncludeDirs...)
- if len(includeDirs) == 0 {
- return
- }
- for _, dir := range includeDirs {
- if _, gen := dir.(android.WritablePath); gen {
- // generated headers are copied via exportedDeps. See below.
- continue
- }
- targetDir := nativeIncludeDir
- if info.hasArchSpecificFlags {
- targetDir = filepath.Join(lib.archType, targetDir)
- }
-
- // TODO(jiyong) copy headers having other suffixes
- headers, _ := ctx.GlobWithDeps(dir.String()+"/**/*.h", nil)
- for _, file := range headers {
- src := android.PathForSource(ctx, file)
- dest := filepath.Join(targetDir, file)
- builder.CopyToSnapshot(src, dest)
- }
- }
-
- genHeaders := lib.exportedDeps
- for _, file := range genHeaders {
- targetDir := nativeGeneratedIncludeDir
- if info.hasArchSpecificFlags {
- targetDir = filepath.Join(lib.archType, targetDir)
- }
- dest := filepath.Join(targetDir, lib.name, file.Rel())
- builder.CopyToSnapshot(file, dest)
- }
- }
-
- if !info.hasArchSpecificFlags {
- printExportedDirCopyCommandsForNativeLibs(info.archVariants[0])
- }
-
- // for each architecture
- for _, av := range info.archVariants {
- builder.CopyToSnapshot(av.outputFile, nativeStubFilePathFor(av))
-
- if info.hasArchSpecificFlags {
- printExportedDirCopyCommandsForNativeLibs(av)
- }
- }
-
- info.generatePrebuiltLibrary(ctx, builder, true)
-
- // This module is for the case when the source tree for the unversioned module
- // doesn't exist (i.e. building in an unbundled tree). "prefer:" is set to false
- // so that this module does not eclipse the unversioned module if it exists.
- info.generatePrebuiltLibrary(ctx, builder, false)
-}
-
-func (info *nativeLibInfo) generatePrebuiltLibrary(ctx android.ModuleContext, builder android.SnapshotBuilder, versioned bool) {
- bp := builder.AndroidBpFile()
- bp.Printfln("cc_prebuilt_library_shared {")
- bp.Indent()
- name := info.name
- if versioned {
- bp.Printfln("name: %q,", builder.VersionedSdkMemberName(name))
- bp.Printfln("sdk_member_name: %q,", name)
- } else {
- bp.Printfln("name: %q,", name)
- bp.Printfln("prefer: false,")
- }
-
- // a function for emitting include dirs
- printExportedDirsForNativeLibs := func(lib archSpecificNativeLibInfo, systemInclude bool) {
- includeDirs := nativeIncludeDirPathsFor(ctx, lib, systemInclude, info.hasArchSpecificFlags)
- if len(includeDirs) == 0 {
- return
- }
- if !systemInclude {
- bp.Printfln("export_include_dirs: [")
- } else {
- bp.Printfln("export_system_include_dirs: [")
- }
- bp.Indent()
- for _, dir := range includeDirs {
- bp.Printfln("%q,", dir)
- }
- bp.Dedent()
- bp.Printfln("],")
- }
-
- if !info.hasArchSpecificFlags {
- printExportedDirsForNativeLibs(info.archVariants[0], false /*systemInclude*/)
- printExportedDirsForNativeLibs(info.archVariants[0], true /*systemInclude*/)
- }
-
- bp.Printfln("arch: {")
- bp.Indent()
- for _, av := range info.archVariants {
- bp.Printfln("%s: {", av.archType)
- bp.Indent()
- bp.Printfln("srcs: [%q],", nativeStubFilePathFor(av))
- if info.hasArchSpecificFlags {
- // export_* properties are added inside the arch: {<arch>: {...}} block
- printExportedDirsForNativeLibs(av, false /*systemInclude*/)
- printExportedDirsForNativeLibs(av, true /*systemInclude*/)
- }
- bp.Dedent()
- bp.Printfln("},") // <arch>
- }
- bp.Dedent()
- bp.Printfln("},") // arch
- bp.Printfln("stl: \"none\",")
- bp.Printfln("system_shared_libs: [],")
- bp.Dedent()
- bp.Printfln("}") // cc_prebuilt_library_shared
- bp.Printfln("")
+ contents := &generatedContents{}
+ generateBpContents(contents, s.builderForTests.bpFile)
+ return contents.content.String()
}
type snapshotBuilder struct {
- ctx android.ModuleContext
- version string
- snapshotDir android.OutputPath
- androidBpFile *generatedFile
- filesToZip android.Paths
- zipsToMerge android.Paths
+ ctx android.ModuleContext
+ sdk *sdk
+ version string
+ snapshotDir android.OutputPath
+ bpFile *bpFile
+ filesToZip android.Paths
+ zipsToMerge android.Paths
+
+ prebuiltModules map[string]*bpModule
+ prebuiltOrder []*bpModule
}
func (s *snapshotBuilder) CopyToSnapshot(src android.Path, dest string) {
@@ -499,23 +360,78 @@
// Repackage the zip file so that the entries are in the destDir directory.
// This will allow the zip file to be merged into the snapshot.
tmpZipPath := android.PathForModuleOut(ctx, "tmp", destDir+".zip").OutputPath
- rb := android.NewRuleBuilder()
- rb.Command().
- BuiltTool(ctx, "zip2zip").
- FlagWithInput("-i ", zipPath).
- FlagWithOutput("-o ", tmpZipPath).
- Flag("**/*:" + destDir)
- rb.Build(pctx, ctx, "repackaging "+destDir,
- "Repackaging zip file "+destDir+" for snapshot "+ctx.ModuleName())
+
+ ctx.Build(pctx, android.BuildParams{
+ Description: "Repackaging zip file " + destDir + " for snapshot " + ctx.ModuleName(),
+ Rule: repackageZip,
+ Input: zipPath,
+ Output: tmpZipPath,
+ Args: map[string]string{
+ "destdir": destDir,
+ },
+ })
// Add the repackaged zip file to the files to merge.
s.zipsToMerge = append(s.zipsToMerge, tmpZipPath)
}
-func (s *snapshotBuilder) AndroidBpFile() android.GeneratedSnapshotFile {
- return s.androidBpFile
+func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType string) android.BpModule {
+ name := member.Name()
+ if s.prebuiltModules[name] != nil {
+ panic(fmt.Sprintf("Duplicate module detected, module %s has already been added", name))
+ }
+
+ m := s.bpFile.newModule(moduleType)
+ m.AddProperty("name", name)
+
+ // Extract visibility information from a member variant. All variants have the same
+ // visibility so it doesn't matter which one is used.
+ visibility := android.EffectiveVisibilityRules(s.ctx, member.Variants()[0])
+ if len(visibility) != 0 {
+ m.AddProperty("visibility", visibility)
+ }
+
+ addHostDeviceSupportedProperties(&s.sdk.ModuleBase, m)
+
+ s.prebuiltModules[name] = m
+ s.prebuiltOrder = append(s.prebuiltOrder, m)
+ return m
}
-func (s *snapshotBuilder) VersionedSdkMemberName(unversionedName string) interface{} {
+func addHostDeviceSupportedProperties(module *android.ModuleBase, bpModule *bpModule) {
+ if !module.DeviceSupported() {
+ bpModule.AddProperty("device_supported", false)
+ }
+ if module.HostSupported() {
+ bpModule.AddProperty("host_supported", true)
+ }
+}
+
+// Get a versioned name appropriate for the SDK snapshot version being taken.
+func (s *snapshotBuilder) versionedSdkMemberName(unversionedName string) string {
return versionedSdkMemberName(s.ctx, unversionedName, s.version)
}
+
+func (s *snapshotBuilder) versionedSdkMemberNames(members []string) []string {
+ var references []string = nil
+ for _, m := range members {
+ references = append(references, s.versionedSdkMemberName(m))
+ }
+ return references
+}
+
+var _ android.SdkMember = (*sdkMember)(nil)
+
+type sdkMember struct {
+ memberType android.SdkMemberType
+ name string
+ variants []android.SdkAware
+}
+
+func (m *sdkMember) Name() string {
+ return m.name
+}
+
+func (m *sdkMember) Variants() []android.SdkAware {
+ return m.variants
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index a876341..1fc94db 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -375,8 +375,8 @@
if isProduct {
// product can't own any sysprop_library now, so product must use public scope
scope = "public"
- } else if isVendor && !isOwnerPlatform {
- // vendor and odm can't use system's internal property.
+ } else if isVendor && isOwnerPlatform {
+ // vendor and odm can only use the public properties from the platform
scope = "public"
}
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 5e0eb35..81f4c53 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -73,7 +73,6 @@
ctx.RegisterModuleType("llndk_library", cc.LlndkLibraryFactory)
ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("image", android.ImageMutator).Parallel()
ctx.BottomUp("link", cc.LinkageMutator).Parallel()
ctx.BottomUp("vndk", cc.VndkMutator).Parallel()
ctx.BottomUp("version", cc.VersionMutator).Parallel()
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 905acfa..c35d8b9 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -197,11 +197,14 @@
return path
}
-func AutoGenRustHostTestConfig(ctx android.ModuleContext, name string, testConfigProp *string,
+func AutoGenRustTestConfig(ctx android.ModuleContext, name string, testConfigProp *string,
testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path {
path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig)
if autogenPath != nil {
templatePathString := "${RustHostTestConfigTemplate}"
+ if ctx.Device() {
+ templatePathString = "${RustDeviceTestConfigTemplate}"
+ }
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
templatePathString = templatePath.String()
diff --git a/tradefed/config.go b/tradefed/config.go
index 8249ffe..a289073 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -31,6 +31,7 @@
pctx.SourcePathVariable("NativeHostTestConfigTemplate", "build/make/core/native_host_test_config_template.xml")
pctx.SourcePathVariable("NativeTestConfigTemplate", "build/make/core/native_test_config_template.xml")
pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
+ pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
pctx.SourcePathVariable("EmptyTestConfig", "build/make/core/empty_test_config.xml")
diff --git a/tradefed/makevars.go b/tradefed/makevars.go
index e6b88ea..d4cf7a8 100644
--- a/tradefed/makevars.go
+++ b/tradefed/makevars.go
@@ -31,6 +31,7 @@
ctx.Strict("NATIVE_HOST_TEST_CONFIG_TEMPLATE", "${NativeHostTestConfigTemplate}")
ctx.Strict("NATIVE_TEST_CONFIG_TEMPLATE", "${NativeTestConfigTemplate}")
ctx.Strict("PYTHON_BINARY_HOST_TEST_CONFIG_TEMPLATE", "${PythonBinaryHostTestConfigTemplate}")
+ ctx.Strict("RUST_DEVICE_TEST_CONFIG_TEMPLATE", "${RustDeviceTestConfigTemplate}")
ctx.Strict("RUST_HOST_TEST_CONFIG_TEMPLATE", "${RustHostTestConfigTemplate}")
ctx.Strict("EMPTY_TEST_CONFIG", "${EmptyTestConfig}")
diff --git a/ui/build/build.go b/ui/build/build.go
index 6a19314..7dfb900 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -33,6 +33,15 @@
// can be parsed as ninja output.
ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build"))
ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), ".out-dir"))
+
+ if buildDateTimeFile, ok := config.environ.Get("BUILD_DATETIME_FILE"); ok {
+ err := ioutil.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0777)
+ if err != nil {
+ ctx.Fatalln("Failed to write BUILD_DATETIME to file:", err)
+ }
+ } else {
+ ctx.Fatalln("Missing BUILD_DATETIME_FILE")
+ }
}
var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(`
diff --git a/ui/build/config.go b/ui/build/config.go
index 876bfe0..565f033 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -15,7 +15,6 @@
package build
import (
- "io/ioutil"
"os"
"path/filepath"
"runtime"
@@ -30,10 +29,11 @@
type configImpl struct {
// From the environment
- arguments []string
- goma bool
- environ *Environment
- distDir string
+ arguments []string
+ goma bool
+ environ *Environment
+ distDir string
+ buildDateTime string
// From the arguments
parallel int
@@ -244,18 +244,14 @@
outDir := ret.OutDir()
buildDateTimeFile := filepath.Join(outDir, "build_date.txt")
- var content string
if buildDateTime, ok := ret.environ.Get("BUILD_DATETIME"); ok && buildDateTime != "" {
- content = buildDateTime
+ ret.buildDateTime = buildDateTime
} else {
- content = strconv.FormatInt(time.Now().Unix(), 10)
+ ret.buildDateTime = strconv.FormatInt(time.Now().Unix(), 10)
}
+
if ctx.Metrics != nil {
- ctx.Metrics.SetBuildDateTime(content)
- }
- err := ioutil.WriteFile(buildDateTimeFile, []byte(content), 0777)
- if err != nil {
- ctx.Fatalln("Failed to write BUILD_DATETIME to file:", err)
+ ctx.Metrics.SetBuildDateTime(ret.buildDateTime)
}
ret.environ.Set("BUILD_DATETIME_FILE", buildDateTimeFile)
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index bc86f0a..64bbbf3 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -19,9 +19,9 @@
"os"
"strconv"
- "android/soong/ui/metrics/metrics_proto"
-
"github.com/golang/protobuf/proto"
+
+ soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
)
const (
@@ -137,13 +137,32 @@
}
}
-func (m *Metrics) Serialize() (data []byte, err error) {
- return proto.Marshal(&m.metrics)
-}
-
// exports the output to the file at outputPath
func (m *Metrics) Dump(outputPath string) (err error) {
- data, err := m.Serialize()
+ return writeMessageToFile(&m.metrics, outputPath)
+}
+
+type CriticalUserJourneysMetrics struct {
+ cujs soong_metrics_proto.CriticalUserJourneysMetrics
+}
+
+func NewCriticalUserJourneysMetrics() *CriticalUserJourneysMetrics {
+ return &CriticalUserJourneysMetrics{}
+}
+
+func (c *CriticalUserJourneysMetrics) Add(name string, metrics *Metrics) {
+ c.cujs.Cujs = append(c.cujs.Cujs, &soong_metrics_proto.CriticalUserJourneyMetrics{
+ Name: proto.String(name),
+ Metrics: &metrics.metrics,
+ })
+}
+
+func (c *CriticalUserJourneysMetrics) Dump(outputPath string) (err error) {
+ return writeMessageToFile(&c.cujs, outputPath)
+}
+
+func writeMessageToFile(pb proto.Message, outputPath string) (err error) {
+ data, err := proto.Marshal(pb)
if err != nil {
return err
}
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index 5486ec1..0fe5a0d 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -509,6 +509,95 @@
return 0
}
+type CriticalUserJourneyMetrics struct {
+ // The name of a critical user journey test.
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ // The metrics produced when running the critical user journey test.
+ Metrics *MetricsBase `protobuf:"bytes,2,opt,name=metrics" json:"metrics,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriticalUserJourneyMetrics) Reset() { *m = CriticalUserJourneyMetrics{} }
+func (m *CriticalUserJourneyMetrics) String() string { return proto.CompactTextString(m) }
+func (*CriticalUserJourneyMetrics) ProtoMessage() {}
+func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) {
+ return fileDescriptor_6039342a2ba47b72, []int{3}
+}
+
+func (m *CriticalUserJourneyMetrics) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriticalUserJourneyMetrics.Unmarshal(m, b)
+}
+func (m *CriticalUserJourneyMetrics) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriticalUserJourneyMetrics.Marshal(b, m, deterministic)
+}
+func (m *CriticalUserJourneyMetrics) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriticalUserJourneyMetrics.Merge(m, src)
+}
+func (m *CriticalUserJourneyMetrics) XXX_Size() int {
+ return xxx_messageInfo_CriticalUserJourneyMetrics.Size(m)
+}
+func (m *CriticalUserJourneyMetrics) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriticalUserJourneyMetrics.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriticalUserJourneyMetrics proto.InternalMessageInfo
+
+func (m *CriticalUserJourneyMetrics) GetName() string {
+ if m != nil && m.Name != nil {
+ return *m.Name
+ }
+ return ""
+}
+
+func (m *CriticalUserJourneyMetrics) GetMetrics() *MetricsBase {
+ if m != nil {
+ return m.Metrics
+ }
+ return nil
+}
+
+type CriticalUserJourneysMetrics struct {
+ // A set of metrics from a run of the critical user journey tests.
+ Cujs []*CriticalUserJourneyMetrics `protobuf:"bytes,1,rep,name=cujs" json:"cujs,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *CriticalUserJourneysMetrics) Reset() { *m = CriticalUserJourneysMetrics{} }
+func (m *CriticalUserJourneysMetrics) String() string { return proto.CompactTextString(m) }
+func (*CriticalUserJourneysMetrics) ProtoMessage() {}
+func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) {
+ return fileDescriptor_6039342a2ba47b72, []int{4}
+}
+
+func (m *CriticalUserJourneysMetrics) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_CriticalUserJourneysMetrics.Unmarshal(m, b)
+}
+func (m *CriticalUserJourneysMetrics) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_CriticalUserJourneysMetrics.Marshal(b, m, deterministic)
+}
+func (m *CriticalUserJourneysMetrics) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_CriticalUserJourneysMetrics.Merge(m, src)
+}
+func (m *CriticalUserJourneysMetrics) XXX_Size() int {
+ return xxx_messageInfo_CriticalUserJourneysMetrics.Size(m)
+}
+func (m *CriticalUserJourneysMetrics) XXX_DiscardUnknown() {
+ xxx_messageInfo_CriticalUserJourneysMetrics.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_CriticalUserJourneysMetrics proto.InternalMessageInfo
+
+func (m *CriticalUserJourneysMetrics) GetCujs() []*CriticalUserJourneyMetrics {
+ if m != nil {
+ return m.Cujs
+ }
+ return nil
+}
+
func init() {
proto.RegisterEnum("soong_build_metrics.MetricsBase_BuildVariant", MetricsBase_BuildVariant_name, MetricsBase_BuildVariant_value)
proto.RegisterEnum("soong_build_metrics.MetricsBase_Arch", MetricsBase_Arch_name, MetricsBase_Arch_value)
@@ -516,59 +605,65 @@
proto.RegisterType((*MetricsBase)(nil), "soong_build_metrics.MetricsBase")
proto.RegisterType((*PerfInfo)(nil), "soong_build_metrics.PerfInfo")
proto.RegisterType((*ModuleTypeInfo)(nil), "soong_build_metrics.ModuleTypeInfo")
+ proto.RegisterType((*CriticalUserJourneyMetrics)(nil), "soong_build_metrics.CriticalUserJourneyMetrics")
+ proto.RegisterType((*CriticalUserJourneysMetrics)(nil), "soong_build_metrics.CriticalUserJourneysMetrics")
}
func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) }
var fileDescriptor_6039342a2ba47b72 = []byte{
- // 769 bytes of a gzipped FileDescriptorProto
+ // 834 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0x6f, 0x6b, 0xdb, 0x46,
- 0x18, 0xaf, 0x62, 0x25, 0x96, 0x1e, 0xc5, 0xae, 0x7a, 0xc9, 0xa8, 0xca, 0x08, 0x33, 0x66, 0x1d,
- 0x7e, 0xb1, 0xba, 0xc5, 0x14, 0x53, 0x4c, 0x19, 0xd8, 0x89, 0x29, 0x25, 0xd8, 0x2e, 0x4a, 0xdc,
- 0x95, 0xed, 0xc5, 0xa1, 0x4a, 0xe7, 0x46, 0x9b, 0xa5, 0x13, 0x77, 0xa7, 0x32, 0x7f, 0x88, 0x7d,
- 0x93, 0x7d, 0xad, 0x7d, 0x8f, 0x71, 0xcf, 0x49, 0x8e, 0x02, 0x81, 0x85, 0xbe, 0x3b, 0x3d, 0xbf,
- 0x3f, 0xf7, 0x7b, 0x4e, 0xba, 0x47, 0xd0, 0xc9, 0x98, 0x12, 0x69, 0x2c, 0x87, 0x85, 0xe0, 0x8a,
- 0x93, 0x13, 0xc9, 0x79, 0xfe, 0x85, 0x7e, 0x2e, 0xd3, 0x6d, 0x42, 0x2b, 0xa8, 0xff, 0x8f, 0x0b,
- 0xde, 0xc2, 0xac, 0x67, 0x91, 0x64, 0xe4, 0x15, 0x9c, 0x1a, 0x42, 0x12, 0x29, 0x46, 0x55, 0x9a,
- 0x31, 0xa9, 0xa2, 0xac, 0x08, 0xac, 0x9e, 0x35, 0x68, 0x85, 0x04, 0xb1, 0x8b, 0x48, 0xb1, 0xeb,
- 0x1a, 0x21, 0xcf, 0xc0, 0x31, 0x8a, 0x34, 0x09, 0x0e, 0x7a, 0xd6, 0xc0, 0x0d, 0xdb, 0xf8, 0xfc,
- 0x3e, 0x21, 0x13, 0x78, 0x56, 0x6c, 0x23, 0xb5, 0xe1, 0x22, 0xa3, 0x5f, 0x99, 0x90, 0x29, 0xcf,
- 0x69, 0xcc, 0x13, 0x96, 0x47, 0x19, 0x0b, 0x5a, 0xc8, 0x7d, 0x5a, 0x13, 0x3e, 0x1a, 0xfc, 0xbc,
- 0x82, 0xc9, 0x73, 0xe8, 0xaa, 0x48, 0x7c, 0x61, 0x8a, 0x16, 0x82, 0x27, 0x65, 0xac, 0x02, 0x1b,
- 0x05, 0x1d, 0x53, 0xfd, 0x60, 0x8a, 0x24, 0x81, 0xd3, 0x8a, 0x66, 0x42, 0x7c, 0x8d, 0x44, 0x1a,
- 0xe5, 0x2a, 0x38, 0xec, 0x59, 0x83, 0xee, 0xe8, 0xc5, 0xf0, 0x9e, 0x9e, 0x87, 0x8d, 0x7e, 0x87,
- 0x33, 0x8d, 0x7c, 0x34, 0xa2, 0x49, 0x6b, 0xbe, 0x7c, 0x17, 0x12, 0xe3, 0xd7, 0x04, 0xc8, 0x0a,
- 0xbc, 0x6a, 0x97, 0x48, 0xc4, 0x37, 0xc1, 0x11, 0x9a, 0x3f, 0xff, 0x5f, 0xf3, 0xa9, 0x88, 0x6f,
- 0x26, 0xed, 0xf5, 0xf2, 0x72, 0xb9, 0xfa, 0x75, 0x19, 0x82, 0xb1, 0xd0, 0x45, 0x32, 0x84, 0x93,
- 0x86, 0xe1, 0x3e, 0x75, 0x1b, 0x5b, 0x7c, 0x72, 0x4b, 0xac, 0x03, 0xfc, 0x0c, 0x55, 0x2c, 0x1a,
- 0x17, 0xe5, 0x9e, 0xee, 0x20, 0xdd, 0x37, 0xc8, 0x79, 0x51, 0xd6, 0xec, 0x4b, 0x70, 0x6f, 0xb8,
- 0xac, 0xc2, 0xba, 0xdf, 0x14, 0xd6, 0xd1, 0x06, 0x18, 0x35, 0x84, 0x0e, 0x9a, 0x8d, 0xf2, 0xc4,
- 0x18, 0xc2, 0x37, 0x19, 0x7a, 0xda, 0x64, 0x94, 0x27, 0xe8, 0xf9, 0x14, 0xda, 0xe8, 0xc9, 0x65,
- 0xe0, 0x61, 0x0f, 0x47, 0xfa, 0x71, 0x25, 0x49, 0xbf, 0xda, 0x8c, 0x4b, 0xca, 0xfe, 0x52, 0x22,
- 0x0a, 0x8e, 0x11, 0xf6, 0x0c, 0x3c, 0xd7, 0xa5, 0x3d, 0x27, 0x16, 0x5c, 0x4a, 0x6d, 0xd1, 0xb9,
- 0xe5, 0x9c, 0xeb, 0xda, 0x4a, 0x92, 0x9f, 0xe0, 0x71, 0x83, 0x83, 0xb1, 0xbb, 0xe6, 0xf3, 0xd9,
- 0xb3, 0x30, 0xc8, 0x0b, 0x38, 0x69, 0xf0, 0xf6, 0x2d, 0x3e, 0x36, 0x07, 0xbb, 0xe7, 0x36, 0x72,
- 0xf3, 0x52, 0xd1, 0x24, 0x15, 0x81, 0x6f, 0x72, 0xf3, 0x52, 0x5d, 0xa4, 0x82, 0xfc, 0x02, 0x9e,
- 0x64, 0xaa, 0x2c, 0xa8, 0xe2, 0x7c, 0x2b, 0x83, 0x27, 0xbd, 0xd6, 0xc0, 0x1b, 0x9d, 0xdd, 0x7b,
- 0x44, 0x1f, 0x98, 0xd8, 0xbc, 0xcf, 0x37, 0x3c, 0x04, 0x54, 0x5c, 0x6b, 0x01, 0x99, 0x80, 0xfb,
- 0x67, 0xa4, 0x52, 0x2a, 0xca, 0x5c, 0x06, 0xe4, 0x21, 0x6a, 0x47, 0xf3, 0xc3, 0x32, 0x97, 0xe4,
- 0x2d, 0x80, 0x61, 0xa2, 0xf8, 0xe4, 0x21, 0x62, 0x17, 0xd1, 0x5a, 0x9d, 0xa7, 0xf9, 0x1f, 0x91,
- 0x51, 0x9f, 0x3e, 0x48, 0x8d, 0x02, 0xad, 0xee, 0xbf, 0x82, 0xe3, 0x3b, 0x17, 0xc5, 0x01, 0x7b,
- 0x7d, 0x35, 0x0f, 0xfd, 0x47, 0xa4, 0x03, 0xae, 0x5e, 0x5d, 0xcc, 0x67, 0xeb, 0x77, 0xbe, 0x45,
- 0xda, 0xa0, 0x2f, 0x97, 0x7f, 0xd0, 0x7f, 0x0b, 0x36, 0x1e, 0xa5, 0x07, 0xf5, 0xa7, 0xe1, 0x3f,
- 0xd2, 0xe8, 0x34, 0x5c, 0xf8, 0x16, 0x71, 0xe1, 0x70, 0x1a, 0x2e, 0xc6, 0xaf, 0xfd, 0x03, 0x5d,
- 0xfb, 0xf4, 0x66, 0xec, 0xb7, 0x08, 0xc0, 0xd1, 0xa7, 0x37, 0x63, 0x3a, 0x7e, 0xed, 0xdb, 0xfd,
- 0xbf, 0x2d, 0x70, 0xea, 0x1c, 0x84, 0x80, 0x9d, 0x30, 0x19, 0xe3, 0x6c, 0x72, 0x43, 0x5c, 0xeb,
- 0x1a, 0x4e, 0x17, 0x33, 0x89, 0x70, 0x4d, 0xce, 0x00, 0xa4, 0x8a, 0x84, 0xc2, 0x71, 0x86, 0x73,
- 0xc7, 0x0e, 0x5d, 0xac, 0xe8, 0x29, 0x46, 0xbe, 0x07, 0x57, 0xb0, 0x68, 0x6b, 0x50, 0x1b, 0x51,
- 0x47, 0x17, 0x10, 0x3c, 0x03, 0xc8, 0x58, 0xc6, 0xc5, 0x8e, 0x96, 0x92, 0xe1, 0x54, 0xb1, 0x43,
- 0xd7, 0x54, 0xd6, 0x92, 0xf5, 0xff, 0xb5, 0xa0, 0xbb, 0xe0, 0x49, 0xb9, 0x65, 0xd7, 0xbb, 0x82,
- 0x61, 0xaa, 0xdf, 0xe1, 0xd8, 0x9c, 0x9b, 0xdc, 0x49, 0xc5, 0x32, 0x4c, 0xd7, 0x1d, 0xbd, 0xbc,
- 0xff, 0xba, 0xdc, 0x91, 0x9a, 0x61, 0x74, 0x85, 0xb2, 0xc6, 0xc5, 0xf9, 0x7c, 0x5b, 0x25, 0x3f,
- 0x80, 0x97, 0xa1, 0x86, 0xaa, 0x5d, 0x51, 0x77, 0x09, 0xd9, 0xde, 0x86, 0xfc, 0x08, 0xdd, 0xbc,
- 0xcc, 0x28, 0xdf, 0x50, 0x53, 0x94, 0xd8, 0x6f, 0x27, 0x3c, 0xce, 0xcb, 0x6c, 0xb5, 0x31, 0xfb,
- 0xc9, 0xfe, 0x4b, 0xf0, 0x1a, 0x7b, 0xdd, 0x7d, 0x17, 0x2e, 0x1c, 0x5e, 0xad, 0x56, 0x4b, 0xfd,
- 0xd2, 0x1c, 0xb0, 0x17, 0xd3, 0xcb, 0xb9, 0x7f, 0x30, 0xfb, 0xee, 0xb7, 0xea, 0xef, 0x51, 0x25,
- 0xa7, 0xf8, 0x4b, 0xf9, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x81, 0xd0, 0x84, 0x23, 0x62, 0x06, 0x00,
- 0x00,
+ 0x18, 0xaf, 0x62, 0x25, 0xb6, 0x1e, 0xc5, 0xae, 0x7a, 0xc9, 0xa8, 0xba, 0x12, 0x66, 0xc4, 0x3a,
+ 0xf2, 0x62, 0x75, 0x8b, 0x29, 0xa1, 0x98, 0x32, 0x48, 0x1c, 0x53, 0xba, 0x60, 0xbb, 0x28, 0x71,
+ 0x57, 0xb6, 0x17, 0x87, 0x22, 0x9d, 0x1b, 0x75, 0x96, 0x4e, 0xdc, 0x9d, 0xca, 0xfc, 0x21, 0xf6,
+ 0x4d, 0xf6, 0xb5, 0xf6, 0x3d, 0xc6, 0x3d, 0x27, 0x39, 0x0a, 0x78, 0x34, 0xf4, 0xdd, 0xe9, 0xf9,
+ 0xfd, 0xb9, 0xdf, 0x73, 0xd2, 0x3d, 0x82, 0x6e, 0xc6, 0x94, 0x48, 0x63, 0x39, 0x28, 0x04, 0x57,
+ 0x9c, 0x1c, 0x48, 0xce, 0xf3, 0x4f, 0xf4, 0xba, 0x4c, 0x57, 0x09, 0xad, 0xa0, 0xe0, 0x1f, 0x07,
+ 0xdc, 0xa9, 0x59, 0x9f, 0x45, 0x92, 0x91, 0x97, 0x70, 0x68, 0x08, 0x49, 0xa4, 0x18, 0x55, 0x69,
+ 0xc6, 0xa4, 0x8a, 0xb2, 0xc2, 0xb7, 0xfa, 0xd6, 0x71, 0x2b, 0x24, 0x88, 0x9d, 0x47, 0x8a, 0x5d,
+ 0xd5, 0x08, 0x79, 0x02, 0x1d, 0xa3, 0x48, 0x13, 0x7f, 0xa7, 0x6f, 0x1d, 0x3b, 0x61, 0x1b, 0x9f,
+ 0xdf, 0x25, 0x64, 0x04, 0x4f, 0x8a, 0x55, 0xa4, 0x96, 0x5c, 0x64, 0xf4, 0x0b, 0x13, 0x32, 0xe5,
+ 0x39, 0x8d, 0x79, 0xc2, 0xf2, 0x28, 0x63, 0x7e, 0x0b, 0xb9, 0x8f, 0x6b, 0xc2, 0x07, 0x83, 0x8f,
+ 0x2b, 0x98, 0x3c, 0x83, 0x9e, 0x8a, 0xc4, 0x27, 0xa6, 0x68, 0x21, 0x78, 0x52, 0xc6, 0xca, 0xb7,
+ 0x51, 0xd0, 0x35, 0xd5, 0xf7, 0xa6, 0x48, 0x12, 0x38, 0xac, 0x68, 0x26, 0xc4, 0x97, 0x48, 0xa4,
+ 0x51, 0xae, 0xfc, 0xdd, 0xbe, 0x75, 0xdc, 0x1b, 0x3e, 0x1f, 0x6c, 0xe9, 0x79, 0xd0, 0xe8, 0x77,
+ 0x70, 0xa6, 0x91, 0x0f, 0x46, 0x34, 0x6a, 0x4d, 0x66, 0x6f, 0x43, 0x62, 0xfc, 0x9a, 0x00, 0x99,
+ 0x83, 0x5b, 0xed, 0x12, 0x89, 0xf8, 0xc6, 0xdf, 0x43, 0xf3, 0x67, 0x5f, 0x35, 0x3f, 0x15, 0xf1,
+ 0xcd, 0xa8, 0xbd, 0x98, 0x5d, 0xcc, 0xe6, 0xbf, 0xcd, 0x42, 0x30, 0x16, 0xba, 0x48, 0x06, 0x70,
+ 0xd0, 0x30, 0xdc, 0xa4, 0x6e, 0x63, 0x8b, 0x8f, 0x6e, 0x89, 0x75, 0x80, 0x9f, 0xa1, 0x8a, 0x45,
+ 0xe3, 0xa2, 0xdc, 0xd0, 0x3b, 0x48, 0xf7, 0x0c, 0x32, 0x2e, 0xca, 0x9a, 0x7d, 0x01, 0xce, 0x0d,
+ 0x97, 0x55, 0x58, 0xe7, 0x9b, 0xc2, 0x76, 0xb4, 0x01, 0x46, 0x0d, 0xa1, 0x8b, 0x66, 0xc3, 0x3c,
+ 0x31, 0x86, 0xf0, 0x4d, 0x86, 0xae, 0x36, 0x19, 0xe6, 0x09, 0x7a, 0x3e, 0x86, 0x36, 0x7a, 0x72,
+ 0xe9, 0xbb, 0xd8, 0xc3, 0x9e, 0x7e, 0x9c, 0x4b, 0x12, 0x54, 0x9b, 0x71, 0x49, 0xd9, 0x5f, 0x4a,
+ 0x44, 0xfe, 0x3e, 0xc2, 0xae, 0x81, 0x27, 0xba, 0xb4, 0xe1, 0xc4, 0x82, 0x4b, 0xa9, 0x2d, 0xba,
+ 0xb7, 0x9c, 0xb1, 0xae, 0xcd, 0x25, 0xf9, 0x09, 0x1e, 0x36, 0x38, 0x18, 0xbb, 0x67, 0x3e, 0x9f,
+ 0x0d, 0x0b, 0x83, 0x3c, 0x87, 0x83, 0x06, 0x6f, 0xd3, 0xe2, 0x43, 0x73, 0xb0, 0x1b, 0x6e, 0x23,
+ 0x37, 0x2f, 0x15, 0x4d, 0x52, 0xe1, 0x7b, 0x26, 0x37, 0x2f, 0xd5, 0x79, 0x2a, 0xc8, 0x2f, 0xe0,
+ 0x4a, 0xa6, 0xca, 0x82, 0x2a, 0xce, 0x57, 0xd2, 0x7f, 0xd4, 0x6f, 0x1d, 0xbb, 0xc3, 0xa3, 0xad,
+ 0x47, 0xf4, 0x9e, 0x89, 0xe5, 0xbb, 0x7c, 0xc9, 0x43, 0x40, 0xc5, 0x95, 0x16, 0x90, 0x11, 0x38,
+ 0x7f, 0x46, 0x2a, 0xa5, 0xa2, 0xcc, 0xa5, 0x4f, 0xee, 0xa3, 0xee, 0x68, 0x7e, 0x58, 0xe6, 0x92,
+ 0xbc, 0x01, 0x30, 0x4c, 0x14, 0x1f, 0xdc, 0x47, 0xec, 0x20, 0x5a, 0xab, 0xf3, 0x34, 0xff, 0x1c,
+ 0x19, 0xf5, 0xe1, 0xbd, 0xd4, 0x28, 0xd0, 0xea, 0xe0, 0x25, 0xec, 0xdf, 0xb9, 0x28, 0x1d, 0xb0,
+ 0x17, 0x97, 0x93, 0xd0, 0x7b, 0x40, 0xba, 0xe0, 0xe8, 0xd5, 0xf9, 0xe4, 0x6c, 0xf1, 0xd6, 0xb3,
+ 0x48, 0x1b, 0xf4, 0xe5, 0xf2, 0x76, 0x82, 0x37, 0x60, 0xe3, 0x51, 0xba, 0x50, 0x7f, 0x1a, 0xde,
+ 0x03, 0x8d, 0x9e, 0x86, 0x53, 0xcf, 0x22, 0x0e, 0xec, 0x9e, 0x86, 0xd3, 0x93, 0x57, 0xde, 0x8e,
+ 0xae, 0x7d, 0x7c, 0x7d, 0xe2, 0xb5, 0x08, 0xc0, 0xde, 0xc7, 0xd7, 0x27, 0xf4, 0xe4, 0x95, 0x67,
+ 0x07, 0x7f, 0x5b, 0xd0, 0xa9, 0x73, 0x10, 0x02, 0x76, 0xc2, 0x64, 0x8c, 0xb3, 0xc9, 0x09, 0x71,
+ 0xad, 0x6b, 0x38, 0x5d, 0xcc, 0x24, 0xc2, 0x35, 0x39, 0x02, 0x90, 0x2a, 0x12, 0x0a, 0xc7, 0x19,
+ 0xce, 0x1d, 0x3b, 0x74, 0xb0, 0xa2, 0xa7, 0x18, 0x79, 0x0a, 0x8e, 0x60, 0xd1, 0xca, 0xa0, 0x36,
+ 0xa2, 0x1d, 0x5d, 0x40, 0xf0, 0x08, 0x20, 0x63, 0x19, 0x17, 0x6b, 0x5a, 0x4a, 0x86, 0x53, 0xc5,
+ 0x0e, 0x1d, 0x53, 0x59, 0x48, 0x16, 0xfc, 0x6b, 0x41, 0x6f, 0xca, 0x93, 0x72, 0xc5, 0xae, 0xd6,
+ 0x05, 0xc3, 0x54, 0x7f, 0xc0, 0xbe, 0x39, 0x37, 0xb9, 0x96, 0x8a, 0x65, 0x98, 0xae, 0x37, 0x7c,
+ 0xb1, 0xfd, 0xba, 0xdc, 0x91, 0x9a, 0x61, 0x74, 0x89, 0xb2, 0xc6, 0xc5, 0xb9, 0xbe, 0xad, 0x92,
+ 0x1f, 0xc0, 0xcd, 0x50, 0x43, 0xd5, 0xba, 0xa8, 0xbb, 0x84, 0x6c, 0x63, 0x43, 0x7e, 0x84, 0x5e,
+ 0x5e, 0x66, 0x94, 0x2f, 0xa9, 0x29, 0x4a, 0xec, 0xb7, 0x1b, 0xee, 0xe7, 0x65, 0x36, 0x5f, 0x9a,
+ 0xfd, 0x64, 0xf0, 0x02, 0xdc, 0xc6, 0x5e, 0x77, 0xdf, 0x85, 0x03, 0xbb, 0x97, 0xf3, 0xf9, 0x4c,
+ 0xbf, 0xb4, 0x0e, 0xd8, 0xd3, 0xd3, 0x8b, 0x89, 0xb7, 0x13, 0xac, 0xe0, 0xfb, 0xb1, 0x48, 0x55,
+ 0x1a, 0x47, 0xab, 0x85, 0x64, 0xe2, 0x57, 0x5e, 0x8a, 0x9c, 0xad, 0xab, 0xdb, 0xbe, 0x39, 0x74,
+ 0xab, 0x71, 0xe8, 0x23, 0x68, 0x57, 0x5d, 0x62, 0x4a, 0x77, 0xd8, 0xff, 0xda, 0xc0, 0x08, 0x6b,
+ 0x41, 0x70, 0x0d, 0x4f, 0xb7, 0xec, 0x26, 0xeb, 0xed, 0xc6, 0x60, 0xc7, 0xe5, 0x67, 0xe9, 0x5b,
+ 0xf8, 0xb1, 0x6e, 0x3f, 0xd9, 0xff, 0x4f, 0x1b, 0xa2, 0xf8, 0xec, 0xbb, 0xdf, 0xab, 0xff, 0x61,
+ 0xa5, 0xa0, 0xf8, 0x93, 0xfc, 0x2f, 0x00, 0x00, 0xff, 0xff, 0x20, 0x07, 0xbc, 0xf0, 0x34, 0x07,
+ 0x00, 0x00,
}
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 93034eb..1ea24bf 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -125,3 +125,16 @@
// The number of logical modules.
optional uint32 num_of_modules = 3;
}
+
+message CriticalUserJourneyMetrics {
+ // The name of a critical user journey test.
+ optional string name = 1;
+
+ // The metrics produced when running the critical user journey test.
+ optional MetricsBase metrics = 2;
+}
+
+message CriticalUserJourneysMetrics {
+ // A set of metrics from a run of the critical user journey tests.
+ repeated CriticalUserJourneyMetrics cujs = 1;
+}
\ No newline at end of file
diff --git a/ui/status/log.go b/ui/status/log.go
index 9090f49..d407248 100644
--- a/ui/status/log.go
+++ b/ui/status/log.go
@@ -180,12 +180,12 @@
func (e *errorProtoLog) Flush() {
data, err := proto.Marshal(&e.errorProto)
if err != nil {
- e.log.Println("Failed to marshal build status proto: %v", err)
+ e.log.Printf("Failed to marshal build status proto: %v\n", err)
return
}
err = ioutil.WriteFile(e.filename, []byte(data), 0644)
if err != nil {
- e.log.Println("Failed to write file %s: %v", e.errorProto, err)
+ e.log.Printf("Failed to write file %s: %v\n", e.filename, err)
}
}
diff --git a/xml/xml_test.go b/xml/xml_test.go
index 0a11566..f42ba77 100644
--- a/xml/xml_test.go
+++ b/xml/xml_test.go
@@ -104,7 +104,7 @@
{rule: "xmllint-minimal", input: "baz.xml"},
} {
t.Run(tc.schemaType, func(t *testing.T) {
- rule := ctx.ModuleForTests(tc.input, "android_arm64_armv8-a").Rule(tc.rule)
+ rule := ctx.ModuleForTests(tc.input, "android_arm64_armv8-a_core").Rule(tc.rule)
assertEqual(t, "input", tc.input, rule.Input.String())
if tc.schemaType != "" {
assertEqual(t, "schema", tc.schema, rule.Args[tc.schemaType])
@@ -112,6 +112,6 @@
})
}
- m := ctx.ModuleForTests("foo.xml", "android_arm64_armv8-a").Module().(*prebuiltEtcXml)
+ m := ctx.ModuleForTests("foo.xml", "android_arm64_armv8-a_core").Module().(*prebuiltEtcXml)
assertEqual(t, "installDir", buildDir+"/target/product/test_device/system/etc", m.InstallDirPath().String())
}