Merge "RBE should not copy source file back to local"
diff --git a/OWNERS b/OWNERS
index f15bd32..f0ccd82 100644
--- a/OWNERS
+++ b/OWNERS
@@ -3,13 +3,18 @@
# AMER
ahumesky@google.com
+alexmarquez@google.com
asmundak@google.com
ccross@android.com
cparsons@google.com
dwillemsen@google.com
eakammer@google.com
+jobredeaux@google.com
joeo@google.com
+lamontjones@google.com
spandandas@google.com
+weiwli@google.com
+yudiliu@google.com
yuntaoxu@google.com
# APAC
diff --git a/README.md b/README.md
index 10ddd73..e92349e 100644
--- a/README.md
+++ b/README.md
@@ -451,15 +451,10 @@
The values of the variables can be set from a product's `BoardConfig.mk` file:
```
-SOONG_CONFIG_NAMESPACES += acme
-SOONG_CONFIG_acme += \
- board \
- feature \
- width \
-
-SOONG_CONFIG_acme_board := soc_a
-SOONG_CONFIG_acme_feature := true
-SOONG_CONFIG_acme_width := 200
+$(call add_soong_config_namespace, acme)
+$(call add_soong_config_var_value, acme, board, soc_a)
+$(call add_soong_config_var_value, acme, feature, true)
+$(call add_soong_config_var_value, acme, width, 200)
```
The `acme_cc_defaults` module type can be used anywhere after the definition in
diff --git a/android/androidmk.go b/android/androidmk.go
index f032f1b..9853d2c 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -571,7 +571,7 @@
if host {
makeOs := amod.Os().String()
- if amod.Os() == Linux || amod.Os() == LinuxBionic {
+ if amod.Os() == Linux || amod.Os() == LinuxBionic || amod.Os() == LinuxMusl {
makeOs = "linux"
}
a.SetString("LOCAL_MODULE_HOST_OS", makeOs)
diff --git a/android/bazel.go b/android/bazel.go
index fa19e52..bebb61b 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -137,12 +137,14 @@
// build/bazel explicitly.
"build/bazel":/* recursive = */ false,
"build/bazel/examples/android_app":/* recursive = */ true,
+ "build/bazel/examples/java":/* recursive = */ true,
"build/bazel/bazel_skylib":/* recursive = */ true,
"build/bazel/rules":/* recursive = */ true,
"build/bazel/rules_cc":/* recursive = */ true,
"build/bazel/tests":/* recursive = */ true,
"build/bazel/platforms":/* recursive = */ true,
"build/bazel/product_variables":/* recursive = */ true,
+ "build/bazel_common_rules":/* recursive = */ true,
"build/pesto":/* recursive = */ true,
// external/bazelbuild-rules_android/... is needed by mixed builds, otherwise mixed builds analysis fails
@@ -160,6 +162,7 @@
bp2buildDefaultConfig = Bp2BuildConfig{
"bionic": Bp2BuildDefaultTrueRecursively,
"build/bazel/examples/apex/minimal": Bp2BuildDefaultTrueRecursively,
+ "development/sdk": Bp2BuildDefaultTrueRecursively,
"external/gwp_asan": Bp2BuildDefaultTrueRecursively,
"system/core/libcutils": Bp2BuildDefaultTrueRecursively,
"system/core/property_service/libpropertyinfoparser": Bp2BuildDefaultTrueRecursively,
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 312f009..9c922dd 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -106,7 +106,7 @@
bazelPath string
outputBase string
workspaceDir string
- buildDir string
+ soongOutDir string
metricsDir string
}
@@ -254,7 +254,7 @@
func bazelPathsFromConfig(c *config) (*bazelPaths, error) {
p := bazelPaths{
- buildDir: c.buildDir,
+ soongOutDir: c.soongOutDir,
}
missingEnvVars := []string{}
if len(c.Getenv("BAZEL_HOME")) > 1 {
@@ -353,7 +353,16 @@
// the invocation returned an error code.
func (r *builtinBazelRunner) issueBazelCommand(paths *bazelPaths, runName bazel.RunName, command bazelCommand,
extraFlags ...string) (string, string, error) {
- cmdFlags := []string{"--output_base=" + absolutePath(paths.outputBase), command.command}
+ cmdFlags := []string{
+ // --noautodetect_server_javabase has the practical consequence of preventing Bazel from
+ // attempting to download rules_java, which is incompatible with
+ // --experimental_repository_disable_download set further below.
+ // rules_java is also not needed until mixed builds start building java targets.
+ // TODO(b/197958133): Once rules_java is pulled into AOSP, remove this flag.
+ "--noautodetect_server_javabase",
+ "--output_base=" + absolutePath(paths.outputBase),
+ command.command,
+ }
cmdFlags = append(cmdFlags, command.expression)
cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(paths, runName))
@@ -382,7 +391,7 @@
bazelCmd.Env = append(os.Environ(),
"HOME="+paths.homeDir,
pwdPrefix(),
- "BUILD_DIR="+absolutePath(paths.buildDir),
+ "BUILD_DIR="+absolutePath(paths.soongOutDir),
// Make OUT_DIR absolute here so tools/bazel.sh uses the correct
// OUT_DIR at <root>/out, instead of <root>/out/soong/workspace/out.
"OUT_DIR="+absolutePath(paths.outDir()),
@@ -599,24 +608,24 @@
// Returns a path containing build-related metadata required for interfacing
// with Bazel. Example: out/soong/bazel.
func (p *bazelPaths) intermediatesDir() string {
- return filepath.Join(p.buildDir, "bazel")
+ return filepath.Join(p.soongOutDir, "bazel")
}
// Returns the path where the contents of the @soong_injection repository live.
// It is used by Soong to tell Bazel things it cannot over the command line.
func (p *bazelPaths) injectedFilesDir() string {
- return filepath.Join(p.buildDir, bazel.SoongInjectionDirName)
+ return filepath.Join(p.soongOutDir, bazel.SoongInjectionDirName)
}
// Returns the path of the synthetic Bazel workspace that contains a symlink
// forest composed the whole source tree and BUILD files generated by bp2build.
func (p *bazelPaths) syntheticWorkspaceDir() string {
- return filepath.Join(p.buildDir, "workspace")
+ return filepath.Join(p.soongOutDir, "workspace")
}
// Returns the path to the top level out dir ($OUT_DIR).
func (p *bazelPaths) outDir() string {
- return filepath.Dir(p.buildDir)
+ return filepath.Dir(p.soongOutDir)
}
// Issues commands to Bazel to receive results for all cquery requests
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index f1fabec..557faea 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -101,7 +101,7 @@
func testBazelContext(t *testing.T, bazelCommandResults map[bazelCommand]string) (*bazelContext, string) {
t.Helper()
p := bazelPaths{
- buildDir: t.TempDir(),
+ soongOutDir: t.TempDir(),
outputBase: "outputbase",
workspaceDir: "workspace_dir",
}
@@ -114,5 +114,5 @@
bazelRunner: runner,
paths: &p,
requests: map[cqueryKey]bool{},
- }, p.buildDir
+ }, p.soongOutDir
}
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index c09d218..a4bd2ef 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -414,7 +414,7 @@
}
outputPath := OutputPath{basePath{"", ""},
- ctx.Config().buildDir,
+ ctx.Config().soongOutDir,
ctx.Config().BazelContext.OutputBase()}
return BazelOutPath{
diff --git a/android/config.go b/android/config.go
index 35403b8..1482e5d 100644
--- a/android/config.go
+++ b/android/config.go
@@ -66,13 +66,13 @@
*config
}
-// BuildDir returns the build output directory for the configuration.
-func (c Config) BuildDir() string {
- return c.buildDir
+// SoongOutDir returns the build output directory for the configuration.
+func (c Config) SoongOutDir() string {
+ return c.soongOutDir
}
-func (c Config) NinjaBuildDir() string {
- return c.buildDir
+func (c Config) OutDir() string {
+ return c.soongOutDir
}
func (c Config) DebugCompilation() bool {
@@ -122,7 +122,7 @@
deviceConfig *deviceConfig
- buildDir string // the path of the build output directory
+ soongOutDir string // the path of the build output directory
moduleListFile string // the path to the file which lists blueprint files to parse.
env map[string]string
@@ -283,11 +283,11 @@
// NullConfig returns a mostly empty Config for use by standalone tools like dexpreopt_gen that
// use the android package.
-func NullConfig(buildDir string) Config {
+func NullConfig(soongOutDir string) Config {
return Config{
config: &config{
- buildDir: buildDir,
- fs: pathtools.OsFs,
+ soongOutDir: soongOutDir,
+ fs: pathtools.OsFs,
},
}
}
@@ -319,7 +319,7 @@
ShippingApiLevel: stringPtr("30"),
},
- buildDir: buildDir,
+ soongOutDir: buildDir,
captureBuild: true,
env: envCopy,
@@ -397,7 +397,7 @@
// multiple runs in the same program execution is carried over (such as Bazel
// context or environment deps).
func ConfigForAdditionalRun(c Config) (Config, error) {
- newConfig, err := NewConfig(c.buildDir, c.moduleListFile, c.env)
+ newConfig, err := NewConfig(c.soongOutDir, c.moduleListFile, c.env)
if err != nil {
return Config{}, err
}
@@ -408,14 +408,14 @@
// NewConfig creates a new Config object. The srcDir argument specifies the path
// to the root source directory. It also loads the config file, if found.
-func NewConfig(buildDir string, moduleListFile string, availableEnv map[string]string) (Config, error) {
+func NewConfig(soongOutDir string, moduleListFile string, availableEnv map[string]string) (Config, error) {
// Make a config with default options.
config := &config{
- ProductVariablesFileName: filepath.Join(buildDir, productVariablesFileName),
+ ProductVariablesFileName: filepath.Join(soongOutDir, productVariablesFileName),
env: availableEnv,
- buildDir: buildDir,
+ soongOutDir: soongOutDir,
multilibConflicts: make(map[ArchType]bool),
moduleListFile: moduleListFile,
@@ -428,7 +428,7 @@
// Soundness check of the build and source directories. This won't catch strange
// configurations with symlinks, but at least checks the obvious case.
- absBuildDir, err := filepath.Abs(buildDir)
+ absBuildDir, err := filepath.Abs(soongOutDir)
if err != nil {
return Config{}, err
}
@@ -448,7 +448,7 @@
return Config{}, err
}
- KatiEnabledMarkerFile := filepath.Join(buildDir, ".soong.kati_enabled")
+ KatiEnabledMarkerFile := filepath.Join(soongOutDir, ".soong.kati_enabled")
if _, err := os.Stat(absolutePath(KatiEnabledMarkerFile)); err == nil {
config.katiEnabled = true
}
@@ -555,12 +555,10 @@
// BlueprintToolLocation returns the directory containing build system tools
// from Blueprint, like soong_zip and merge_zips.
-func (c *config) BlueprintToolLocation() string {
- return filepath.Join(c.buildDir, "host", c.PrebuiltOS(), "bin")
+func (c *config) HostToolDir() string {
+ return filepath.Join(c.soongOutDir, "host", c.PrebuiltOS(), "bin")
}
-var _ bootstrap.ConfigBlueprintToolLocation = (*config)(nil)
-
func (c *config) HostToolPath(ctx PathContext, tool string) Path {
return PathForOutput(ctx, "host", c.PrebuiltOS(), "bin", tool)
}
@@ -1665,8 +1663,9 @@
return ConfiguredJarList{apexes, jars}
}
-// Filter keeps the entries if a jar appears in the given list of jars to keep; returns a new list.
-func (l *ConfiguredJarList) Filter(jarsToKeep []string) ConfiguredJarList {
+// Filter keeps the entries if a jar appears in the given list of jars to keep. Returns a new list
+// and any remaining jars that are not on this list.
+func (l *ConfiguredJarList) Filter(jarsToKeep []string) (ConfiguredJarList, []string) {
var apexes []string
var jars []string
@@ -1677,7 +1676,7 @@
}
}
- return ConfiguredJarList{apexes, jars}
+ return ConfiguredJarList{apexes, jars}, RemoveListFromList(jarsToKeep, jars)
}
// CopyOfJars returns a copy of the list of strings containing jar module name
diff --git a/android/fixture.go b/android/fixture.go
index fd051a7..728f031 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -834,7 +834,7 @@
func (r *TestResult) NormalizePathForTesting(path Path) string {
pathContext := PathContextForTesting(r.Config)
pathAsString := path.String()
- if rel, isRel := MaybeRel(pathContext, r.Config.BuildDir(), pathAsString); isRel {
+ if rel, isRel := MaybeRel(pathContext, r.Config.SoongOutDir(), pathAsString); isRel {
return rel
}
return pathAsString
diff --git a/android/license_sdk_member.go b/android/license_sdk_member.go
index cd36ed6..2ce921b 100644
--- a/android/license_sdk_member.go
+++ b/android/license_sdk_member.go
@@ -31,9 +31,9 @@
SdkMemberTypeBase
}
-func (l *licenseSdkMemberType) AddDependencies(mctx BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+func (l *licenseSdkMemberType) AddDependencies(ctx SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
// Add dependencies onto the license module from the sdk module.
- mctx.AddDependency(mctx.Module(), dependencyTag, names...)
+ ctx.AddDependency(ctx.Module(), dependencyTag, names...)
}
func (l *licenseSdkMemberType) IsInstance(module Module) bool {
diff --git a/android/module.go b/android/module.go
index b571f15..cc03418 100644
--- a/android/module.go
+++ b/android/module.go
@@ -986,10 +986,13 @@
// Device is built by default. Host and HostCross are not supported.
DeviceSupported = deviceSupported | deviceDefault
- // Device is built by default. Host and HostCross are supported.
+ // By default, _only_ device variant is built. Device variant can be disabled with `device_supported: false`
+ // Host and HostCross are disabled by default and can be enabled with `host_supported: true`
HostAndDeviceSupported = hostSupported | hostCrossSupported | deviceSupported | deviceDefault
// Host, HostCross, and Device are built by default.
+ // Building Device can be disabled with `device_supported: false`
+ // Building Host and HostCross can be disabled with `host_supported: false`
HostAndDeviceDefault = hostSupported | hostCrossSupported | hostDefault |
deviceSupported | deviceDefault
diff --git a/android/paths.go b/android/paths.go
index 71caaab..763cd7c 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -186,13 +186,13 @@
// A standard build has the following structure:
// ../top/
// out/ - make install files go here.
- // out/soong - this is the buildDir passed to NewTestConfig()
+ // out/soong - this is the soongOutDir passed to NewTestConfig()
// ... - the source files
//
// This function converts a path so that it appears relative to the ../top/ directory, i.e.
- // * Make install paths, which have the pattern "buildDir/../<path>" are converted into the top
+ // * Make install paths, which have the pattern "soongOutDir/../<path>" are converted into the top
// relative path "out/<path>"
- // * Soong install paths and other writable paths, which have the pattern "buildDir/<path>" are
+ // * Soong install paths and other writable paths, which have the pattern "soongOutDir/<path>" are
// converted into the top relative path "out/soong/<path>".
// * Source paths are already relative to the top.
// * Phony paths are not relative to anything.
@@ -211,7 +211,7 @@
Path
// return the path to the build directory.
- getBuildDir() string
+ getSoongOutDir() string
// the writablePath method doesn't directly do anything,
// but it allows a struct to distinguish between whether or not it implements the WritablePath interface
@@ -992,7 +992,7 @@
}
// absolute path already checked by validateSafePath
- if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
+ if strings.HasPrefix(ret.String(), ctx.Config().soongOutDir) {
return ret, fmt.Errorf("source path %q is in output", ret.String())
}
@@ -1008,7 +1008,7 @@
}
// absolute path already checked by validatePath
- if strings.HasPrefix(ret.String(), ctx.Config().buildDir) {
+ if strings.HasPrefix(ret.String(), ctx.Config().soongOutDir) {
return ret, fmt.Errorf("source path %q is in output", ret.String())
}
@@ -1150,8 +1150,8 @@
type OutputPath struct {
basePath
- // The soong build directory, i.e. Config.BuildDir()
- buildDir string
+ // The soong build directory, i.e. Config.SoongOutDir()
+ soongOutDir string
fullPath string
}
@@ -1167,8 +1167,8 @@
return p
}
-func (p OutputPath) getBuildDir() string {
- return p.buildDir
+func (p OutputPath) getSoongOutDir() string {
+ return p.soongOutDir
}
func (p OutputPath) RelativeToTop() Path {
@@ -1176,8 +1176,8 @@
}
func (p OutputPath) outputPathRelativeToTop() OutputPath {
- p.fullPath = StringPathRelativeToTop(p.buildDir, p.fullPath)
- p.buildDir = OutSoongDir
+ p.fullPath = StringPathRelativeToTop(p.soongOutDir, p.fullPath)
+ p.soongOutDir = OutSoongDir
return p
}
@@ -1218,12 +1218,12 @@
if err != nil {
reportPathError(ctx, err)
}
- fullPath := filepath.Join(ctx.Config().buildDir, path)
+ fullPath := filepath.Join(ctx.Config().soongOutDir, path)
path = fullPath[len(fullPath)-len(path):]
- return OutputPath{basePath{path, ""}, ctx.Config().buildDir, fullPath}
+ return OutputPath{basePath{path, ""}, ctx.Config().soongOutDir, fullPath}
}
-// PathsForOutput returns Paths rooted from buildDir
+// PathsForOutput returns Paths rooted from soongOutDir
func PathsForOutput(ctx PathContext, paths []string) WritablePaths {
ret := make(WritablePaths, len(paths))
for i, path := range paths {
@@ -1544,8 +1544,8 @@
type InstallPath struct {
basePath
- // The soong build directory, i.e. Config.BuildDir()
- buildDir string
+ // The soong build directory, i.e. Config.SoongOutDir()
+ soongOutDir string
// partitionDir is the part of the InstallPath that is automatically determined according to the context.
// For example, it is host/<os>-<arch> for host modules, and target/product/<device>/<partition> for device modules.
@@ -1565,12 +1565,12 @@
func (p InstallPath) RelativeToTop() Path {
ensureTestOnly()
- p.buildDir = OutSoongDir
+ p.soongOutDir = OutSoongDir
return p
}
-func (p InstallPath) getBuildDir() string {
- return p.buildDir
+func (p InstallPath) getSoongOutDir() string {
+ return p.soongOutDir
}
func (p InstallPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
@@ -1585,9 +1585,9 @@
func (p InstallPath) String() string {
if p.makePath {
// Make path starts with out/ instead of out/soong.
- return filepath.Join(p.buildDir, "../", p.path)
+ return filepath.Join(p.soongOutDir, "../", p.path)
} else {
- return filepath.Join(p.buildDir, p.path)
+ return filepath.Join(p.soongOutDir, p.path)
}
}
@@ -1596,9 +1596,9 @@
// The ./soong is dropped if the install path is for Make.
func (p InstallPath) PartitionDir() string {
if p.makePath {
- return filepath.Join(p.buildDir, "../", p.partitionDir)
+ return filepath.Join(p.soongOutDir, "../", p.partitionDir)
} else {
- return filepath.Join(p.buildDir, p.partitionDir)
+ return filepath.Join(p.soongOutDir, p.partitionDir)
}
}
@@ -1694,7 +1694,7 @@
base := InstallPath{
basePath: basePath{partionPath, ""},
- buildDir: ctx.Config().buildDir,
+ soongOutDir: ctx.Config().soongOutDir,
partitionDir: partionPath,
makePath: false,
}
@@ -1705,7 +1705,7 @@
func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
base := InstallPath{
basePath: basePath{prefix, ""},
- buildDir: ctx.Config().buildDir,
+ soongOutDir: ctx.Config().soongOutDir,
partitionDir: prefix,
makePath: false,
}
@@ -1851,7 +1851,7 @@
func (p PhonyPath) writablePath() {}
-func (p PhonyPath) getBuildDir() string {
+func (p PhonyPath) getSoongOutDir() string {
// A phone path cannot contain any / so cannot be relative to the build directory.
return ""
}
diff --git a/android/sdk.go b/android/sdk.go
index da740f3..b8f76c1 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -401,26 +401,26 @@
ExportMember() bool
}
-var _ SdkMemberTypeDependencyTag = (*sdkMemberDependencyTag)(nil)
-var _ ReplaceSourceWithPrebuilt = (*sdkMemberDependencyTag)(nil)
+var _ SdkMemberTypeDependencyTag = (*sdkMemberTypeDependencyTag)(nil)
+var _ ReplaceSourceWithPrebuilt = (*sdkMemberTypeDependencyTag)(nil)
-type sdkMemberDependencyTag struct {
+type sdkMemberTypeDependencyTag struct {
blueprint.BaseDependencyTag
memberType SdkMemberType
export bool
}
-func (t *sdkMemberDependencyTag) SdkMemberType(_ Module) SdkMemberType {
+func (t *sdkMemberTypeDependencyTag) SdkMemberType(_ Module) SdkMemberType {
return t.memberType
}
-func (t *sdkMemberDependencyTag) ExportMember() bool {
+func (t *sdkMemberTypeDependencyTag) ExportMember() bool {
return t.export
}
// Prevent dependencies from the sdk/module_exports onto their members from being
// replaced with a preferred prebuilt.
-func (t *sdkMemberDependencyTag) ReplaceSourceWithPrebuilt() bool {
+func (t *sdkMemberTypeDependencyTag) ReplaceSourceWithPrebuilt() bool {
return false
}
@@ -428,7 +428,7 @@
// dependencies added by the tag to be added to the sdk as the specified SdkMemberType and exported
// (or not) as specified by the export parameter.
func DependencyTagForSdkMemberType(memberType SdkMemberType, export bool) SdkMemberTypeDependencyTag {
- return &sdkMemberDependencyTag{memberType: memberType, export: export}
+ return &sdkMemberTypeDependencyTag{memberType: memberType, export: export}
}
// Interface that must be implemented for every type that can be a member of an
@@ -475,7 +475,7 @@
// 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)
+ AddDependencies(ctx SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string)
// Return true if the supplied module is an instance of this member type.
//
@@ -529,6 +529,12 @@
CreateVariantPropertiesStruct() SdkMemberProperties
}
+// SdkDependencyContext provides access to information needed by the SdkMemberType.AddDependencies()
+// implementations.
+type SdkDependencyContext interface {
+ BottomUpMutatorContext
+}
+
// Base type for SdkMemberType implementations.
type SdkMemberTypeBase struct {
PropertyName string
@@ -570,9 +576,6 @@
type SdkMemberTypesRegistry struct {
// The list of types sorted by property name.
list []SdkMemberType
-
- // The key that uniquely identifies this registry instance.
- key OnceKey
}
func (r *SdkMemberTypesRegistry) copyAndAppend(memberType SdkMemberType) *SdkMemberTypesRegistry {
@@ -592,18 +595,9 @@
return t1.SdkPropertyName() < t2.SdkPropertyName()
})
- // Generate a key that identifies the slice of SdkMemberTypes by joining the property names
- // from all the SdkMemberType .
- var properties []string
- for _, t := range list {
- properties = append(properties, t.SdkPropertyName())
- }
- key := NewOnceKey(strings.Join(properties, "|"))
-
// Create a new registry so the pointer uniquely identifies the set of registered types.
return &SdkMemberTypesRegistry{
list: list,
- key: key,
}
}
@@ -616,8 +610,10 @@
return NewCustomOnceKey(r)
}
-// The set of registered SdkMemberTypes, one for sdk module and one for module_exports.
+// The set of registered SdkMemberTypes for module_exports modules.
var ModuleExportsMemberTypes = &SdkMemberTypesRegistry{}
+
+// The set of registered SdkMemberTypes for sdk modules.
var SdkMemberTypes = &SdkMemberTypesRegistry{}
// Register an SdkMemberType object to allow them to be used in the sdk and sdk_snapshot module
diff --git a/android/singleton.go b/android/singleton.go
index bb6614d..7ff96c9 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -54,10 +54,10 @@
RequireNinjaVersion(major, minor, micro int)
- // SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable
+ // SetOutDir sets the value of the top-level "builddir" Ninja variable
// that controls where Ninja stores its build log files. This value can be
// set at most one time for a single build, later calls are ignored.
- SetNinjaBuildDir(pctx PackageContext, value string)
+ SetOutDir(pctx PackageContext, value string)
// Eval takes a string with embedded ninja variables, and returns a string
// with all of the variables recursively expanded. Any variables references
@@ -180,8 +180,8 @@
addPhony(s.Config(), name, deps...)
}
-func (s *singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) {
- s.SingletonContext.SetNinjaBuildDir(pctx.PackageContext, value)
+func (s *singletonContextAdaptor) SetOutDir(pctx PackageContext, value string) {
+ s.SingletonContext.SetOutDir(pctx.PackageContext, value)
}
func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) {
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 289e910..17f6d66 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -122,15 +122,10 @@
// }
//
// If an acme BoardConfig.mk file contained:
-//
-// SOONG_CONFIG_NAMESPACES += acme
-// SOONG_CONFIG_acme += \
-// board \
-// feature \
-//
-// SOONG_CONFIG_acme_board := soc_a
-// SOONG_CONFIG_acme_feature := true
-// SOONG_CONFIG_acme_width := 200
+// $(call add_sonng_config_namespace, acme)
+// $(call add_soong_config_var_value, acme, board, soc_a)
+// $(call add_soong_config_var_value, acme, feature, true)
+// $(call add_soong_config_var_value, acme, width, 200)
//
// Then libacme_foo would build with cflags "-DGENERIC -DSOC_A -DFEATURE -DWIDTH=200".
//
diff --git a/android/test_asserts.go b/android/test_asserts.go
index edeb408..064f656 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -77,14 +77,14 @@
// StringPathRelativeToTop on the actual string path.
func AssertStringPathRelativeToTopEquals(t *testing.T, message string, config Config, expected string, actual string) {
t.Helper()
- AssertStringEquals(t, message, expected, StringPathRelativeToTop(config.buildDir, actual))
+ AssertStringEquals(t, message, expected, StringPathRelativeToTop(config.soongOutDir, actual))
}
// AssertStringPathsRelativeToTopEquals checks if the expected value is equal to the result of
// calling StringPathsRelativeToTop on the actual string paths.
func AssertStringPathsRelativeToTopEquals(t *testing.T, message string, config Config, expected []string, actual []string) {
t.Helper()
- AssertDeepEquals(t, message, expected, StringPathsRelativeToTop(config.buildDir, actual))
+ AssertDeepEquals(t, message, expected, StringPathsRelativeToTop(config.soongOutDir, actual))
}
// AssertErrorMessageEquals checks if the error is not nil and has the expected message. If it does
diff --git a/android/testing.go b/android/testing.go
index 6ba8e3c..e25e5c5 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -664,15 +664,15 @@
// containing at most one instance of the temporary build directory at the start of the path while
// this assumes that there can be any number at any position.
func normalizeStringRelativeToTop(config Config, s string) string {
- // The buildDir usually looks something like: /tmp/testFoo2345/001
+ // The soongOutDir usually looks something like: /tmp/testFoo2345/001
//
- // Replace any usage of the buildDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with
+ // Replace any usage of the soongOutDir with out/soong, e.g. replace "/tmp/testFoo2345/001" with
// "out/soong".
- outSoongDir := filepath.Clean(config.buildDir)
+ outSoongDir := filepath.Clean(config.soongOutDir)
re := regexp.MustCompile(`\Q` + outSoongDir + `\E\b`)
s = re.ReplaceAllString(s, "out/soong")
- // Replace any usage of the buildDir/.. with out, e.g. replace "/tmp/testFoo2345" with
+ // Replace any usage of the soongOutDir/.. with out, e.g. replace "/tmp/testFoo2345" with
// "out". This must come after the previous replacement otherwise this would replace
// "/tmp/testFoo2345/001" with "out/001" instead of "out/soong".
outDir := filepath.Dir(outSoongDir)
@@ -991,7 +991,7 @@
}
p := path.String()
if w, ok := path.(WritablePath); ok {
- rel, err := filepath.Rel(w.getBuildDir(), p)
+ rel, err := filepath.Rel(w.getSoongOutDir(), p)
if err != nil {
panic(err)
}
diff --git a/android/variable.go b/android/variable.go
index 5cf9aa8..a1af527 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -46,6 +46,10 @@
Java_resource_dirs []string
}
+ Platform_sdk_extension_version struct {
+ Cmd *string
+ }
+
// unbundled_build is a catch-all property to annotate modules that don't build in one or
// more unbundled branches, usually due to dependencies missing from the manifest.
Unbundled_build struct {
@@ -108,6 +112,8 @@
Static_libs []string
Whole_static_libs []string
Shared_libs []string
+
+ Cmdline []string
}
// eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging
@@ -170,6 +176,7 @@
Platform_sdk_codename *string `json:",omitempty"`
Platform_sdk_version_or_codename *string `json:",omitempty"`
Platform_sdk_final *bool `json:",omitempty"`
+ Platform_sdk_extension_version *int `json:",omitempty"`
Platform_version_active_codenames []string `json:",omitempty"`
Platform_vndk_version *string `json:",omitempty"`
Platform_systemsdk_versions []string `json:",omitempty"`
diff --git a/android/writedocs.go b/android/writedocs.go
index 67b9aa3..c380a3d 100644
--- a/android/writedocs.go
+++ b/android/writedocs.go
@@ -34,12 +34,12 @@
type docsSingleton struct{}
func primaryBuilderPath(ctx SingletonContext) Path {
- buildDir := absolutePath(ctx.Config().BuildDir())
+ soongOutDir := absolutePath(ctx.Config().SoongOutDir())
binary := absolutePath(os.Args[0])
- primaryBuilder, err := filepath.Rel(buildDir, binary)
+ primaryBuilder, err := filepath.Rel(soongOutDir, binary)
if err != nil {
ctx.Errorf("path to primary builder %q is not in build dir %q (%q)",
- os.Args[0], ctx.Config().BuildDir(), err)
+ os.Args[0], ctx.Config().SoongOutDir(), err)
}
return PathForOutput(ctx, primaryBuilder)
diff --git a/apex/androidmk.go b/apex/androidmk.go
index ebf0833..2f10904 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -212,7 +212,7 @@
}
if host {
makeOs := fi.module.Target().Os.String()
- if fi.module.Target().Os == android.Linux || fi.module.Target().Os == android.LinuxBionic {
+ if fi.module.Target().Os == android.Linux || fi.module.Target().Os == android.LinuxBionic || fi.module.Target().Os == android.LinuxMusl {
makeOs = "linux"
}
fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", makeOs)
diff --git a/apex/apex.go b/apex/apex.go
index e1fca67..6bafcae 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -117,9 +117,6 @@
// List of platform_compat_config files that are embedded inside this APEX bundle.
Compat_configs []string
- // List of BPF programs inside this APEX bundle.
- Bpfs []string
-
// List of filesystem images that are embedded inside this APEX bundle.
Filesystems []string
@@ -297,6 +294,9 @@
// List of runtime resource overlays (RROs) that are embedded inside this APEX.
Rros []string
+ // List of BPF programs inside this APEX bundle.
+ Bpfs []string
+
// Names of modules to be overridden. Listed modules can only be other binaries (in Make or
// Soong). This does not completely prevent installation of the overridden binaries, but if
// both binaries would be installed by default (in PRODUCT_PACKAGES) the other binary will
@@ -780,7 +780,6 @@
ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments...)
ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.Systemserverclasspath_fragments...)
ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
- ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.properties.Bpfs...)
ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
ctx.AddFarVariationDependencies(commonVariation, compatConfigTag, a.properties.Compat_configs...)
@@ -813,6 +812,7 @@
commonVariation := ctx.Config().AndroidCommonTarget.Variations()
ctx.AddFarVariationDependencies(commonVariation, androidAppTag, a.overridableProperties.Apps...)
+ ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.overridableProperties.Bpfs...)
ctx.AddFarVariationDependencies(commonVariation, rroTag, a.overridableProperties.Rros...)
// Dependencies for signing
diff --git a/apex/apex_test.go b/apex/apex_test.go
index f07bf63..daaa5cb 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1874,6 +1874,45 @@
expectNoLink("libx", "shared_apex10000", "libz", "shared")
}
+func TestApexMinSdkVersion_crtobjectInVendorApex(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ updatable: false,
+ vendor: true,
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ vendor_available: true,
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ min_sdk_version: "29",
+ }
+ `)
+
+ vendorVariant := "android_vendor.29_arm64_armv8-a"
+
+ // First check that the correct variant of crtbegin_so is used.
+ ldRule := ctx.ModuleForTests("mylib", vendorVariant+"_shared_apex29").Rule("ld")
+ crtBegin := names(ldRule.Args["crtBegin"])
+ ensureListContains(t, crtBegin, "out/soong/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"crtbegin_so/"+vendorVariant+"_apex29/crtbegin_so.o")
+
+ // Ensure that the crtbegin_so used by the APEX is targeting 29
+ cflags := ctx.ModuleForTests("crtbegin_so", vendorVariant+"_apex29").Rule("cc").Args["cFlags"]
+ android.AssertStringDoesContain(t, "cflags", cflags, "-target aarch64-linux-android29")
+}
+
func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
ctx := testApex(t, `
apex {
@@ -4891,7 +4930,7 @@
}
}
if !foundLibfooJar {
- t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().BuildDir(), s.AllOutputs()))
+ t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().SoongOutDir(), s.AllOutputs()))
}
}
@@ -5090,6 +5129,12 @@
// find the dex boot jar in it. We either need to disable the source libfoo
// or make the prebuilt libfoo preferred.
testDexpreoptWithApexes(t, bp, "module libfoo does not provide a dex boot jar", preparer, fragment)
+ // dexbootjar check is skipped if AllowMissingDependencies is true
+ preparerAllowMissingDeps := android.GroupFixturePreparers(
+ preparer,
+ android.PrepareForTestWithAllowMissingDependencies,
+ )
+ testDexpreoptWithApexes(t, bp, "", preparerAllowMissingDeps, fragment)
})
t.Run("prebuilt library preferred with source", func(t *testing.T) {
@@ -6034,6 +6079,7 @@
name: "myapex",
key: "myapex.key",
apps: ["app"],
+ bpfs: ["bpf"],
overrides: ["oldapex"],
updatable: false,
}
@@ -6042,6 +6088,7 @@
name: "override_myapex",
base: "myapex",
apps: ["override_app"],
+ bpfs: ["override_bpf"],
overrides: ["unknownapex"],
logging_parent: "com.foo.bar",
package_name: "test.overridden.package",
@@ -6080,6 +6127,16 @@
base: "app",
package_name: "bar",
}
+
+ bpf {
+ name: "bpf",
+ srcs: ["bpf.c"],
+ }
+
+ bpf {
+ name: "override_bpf",
+ srcs: ["override_bpf.c"],
+ }
`, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"}))
originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(android.OverridableModule)
@@ -6098,6 +6155,9 @@
ensureNotContains(t, copyCmds, "image.apex/app/app/app.apk")
ensureContains(t, copyCmds, "image.apex/app/override_app/override_app.apk")
+ ensureNotContains(t, copyCmds, "image.apex/etc/bpf/bpf.o")
+ ensureContains(t, copyCmds, "image.apex/etc/bpf/override_bpf.o")
+
apexBundle := module.Module().(*apexBundle)
name := apexBundle.Name()
if name != "override_myapex" {
@@ -6120,10 +6180,12 @@
data.Custom(&builder, name, "TARGET_", "", data)
androidMk := builder.String()
ensureContains(t, androidMk, "LOCAL_MODULE := override_app.override_myapex")
+ ensureContains(t, androidMk, "LOCAL_MODULE := override_bpf.o.override_myapex")
ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.override_myapex")
ensureContains(t, androidMk, "LOCAL_MODULE_STEM := override_myapex.apex")
ensureContains(t, androidMk, "LOCAL_OVERRIDES_MODULES := unknownapex myapex")
ensureNotContains(t, androidMk, "LOCAL_MODULE := app.myapex")
+ ensureNotContains(t, androidMk, "LOCAL_MODULE := bpf.myapex")
ensureNotContains(t, androidMk, "LOCAL_MODULE := override_app.myapex")
ensureNotContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.myapex")
ensureNotContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.apex")
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
index e2d8465..60f18bd 100644
--- a/apex/classpath_element_test.go
+++ b/apex/classpath_element_test.go
@@ -159,11 +159,6 @@
],
}
- bootclasspath_fragment {
- name: "non-apex-fragment",
- contents: ["othersdklibrary"],
- }
-
apex {
name: "otherapex",
key: "otherapex.key",
@@ -213,7 +208,6 @@
myFragment := result.Module("mybootclasspath-fragment", "android_common_apex10000")
myBar := result.Module("bar", "android_common_apex10000")
- nonApexFragment := result.Module("non-apex-fragment", "android_common")
other := result.Module("othersdklibrary", "android_common_apex10000")
otherApexLibrary := result.Module("otherapexlibrary", "android_common_apex10000")
@@ -253,15 +247,6 @@
assertElementsEquals(t, "elements", expectedElements, elements)
})
- // Verify that CreateClasspathElements detects when a fragment does not have an associated apex.
- t.Run("non apex fragment", func(t *testing.T) {
- ctx := newCtx()
- elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{nonApexFragment})
- android.FailIfNoMatchingErrors(t, "fragment non-apex-fragment{.*} is not part of an apex", ctx.errs)
- expectedElements := java.ClasspathElements{}
- assertElementsEquals(t, "elements", expectedElements, elements)
- })
-
// Verify that CreateClasspathElements detects when an apex has multiple fragments.
t.Run("multiple fragments for same apex", func(t *testing.T) {
ctx := newCtx()
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index e0421f6..513ddc0 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -543,3 +543,140 @@
"out/soong/target/product/test_device/system/etc/classpaths",
)
}
+
+func TestBootJarNotInApex(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ java.FixtureConfigureApexBootJars("myapex:foo"),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `dependency "foo" of "myplatform-bootclasspath" missing variant`)).
+ RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: [
+ "myapex",
+ ],
+ }
+
+ bootclasspath_fragment {
+ name: "not-in-apex-fragment",
+ contents: [
+ "foo",
+ ],
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+ }
+ `)
+}
+
+func TestBootFragmentNotInApex(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ java.FixtureConfigureApexBootJars("myapex:foo"),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `library foo.*have no corresponding fragment.*`)).RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ java_libs: ["foo"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["foo"],
+ }
+
+ bootclasspath_fragment {
+ name: "not-in-apex-fragment",
+ contents: ["foo"],
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+ }
+ `)
+}
+
+func TestNonBootJarInFragment(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ java.FixtureConfigureApexBootJars("myapex:foo"),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `in contents must also be declared in PRODUCT_APEX_BOOT_JARS`)).
+ RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: ["apex-fragment"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["foo"],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["bar"],
+ }
+
+ bootclasspath_fragment {
+ name: "apex-fragment",
+ contents: ["foo", "bar"],
+ apex_available:[ "myapex" ],
+ }
+
+ platform_bootclasspath {
+ name: "myplatform-bootclasspath",
+ fragments: [{
+ apex: "myapex",
+ module:"apex-fragment",
+ }],
+ }
+ `)
+}
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
index a64c6f4..a8d5931 100644
--- a/apex/systemserver_classpath_fragment_test.go
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -130,3 +130,54 @@
`mysystemserverclasspathfragment`,
})
}
+
+func TestSystemServerClasspathFragmentWithContentNotInMake(t *testing.T) {
+ android.GroupFixturePreparers(
+ prepareForTestWithSystemserverclasspathFragment,
+ prepareForTestWithMyapex,
+ dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+ `in contents must also be declared in PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS`)).
+ RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ systemserverclasspath_fragments: [
+ "mysystemserverclasspathfragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ }
+
+ systemserverclasspath_fragment {
+ name: "mysystemserverclasspathfragment",
+ contents: [
+ "foo",
+ "bar",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ }
+ `)
+}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 78e3a74..b1ccc96 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -42,6 +42,7 @@
"performance_test.go",
"prebuilt_etc_conversion_test.go",
"python_binary_conversion_test.go",
+ "python_library_conversion_test.go",
"sh_conversion_test.go",
"testing.go",
],
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index a64d474..f652a35 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -14,14 +14,20 @@
package bp2build
+/*
+For shareable/common functionality for conversion from soong-module to build files
+for queryview/bp2build
+*/
+
import (
- "android/soong/android"
- "android/soong/bazel"
"fmt"
"reflect"
"sort"
"strings"
+ "android/soong/android"
+ "android/soong/bazel"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index bff192f..c840016 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -15,10 +15,10 @@
package bp2build
import (
+ "testing"
+
"android/soong/android"
"android/soong/cc"
- "strings"
- "testing"
)
const (
@@ -54,59 +54,6 @@
ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
}
-func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) {
- t.Helper()
- dir := "."
- filesystem := make(map[string][]byte)
- toParse := []string{
- "Android.bp",
- }
- for f, content := range tc.filesystem {
- if strings.HasSuffix(f, "Android.bp") {
- toParse = append(toParse, f)
- }
- filesystem[f] = []byte(content)
- }
- config := android.TestConfig(buildDir, nil, tc.blueprint, filesystem)
- ctx := android.NewTestContext(config)
-
- registerModuleTypes(ctx)
- ctx.RegisterModuleType(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestFactory)
- ctx.RegisterBp2BuildConfig(bp2buildConfig)
- ctx.RegisterBp2BuildMutator(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestBp2BuildMutator)
- ctx.RegisterForBazelConversion()
-
- _, errs := ctx.ParseFileList(dir, toParse)
- if errored(t, tc.description, errs) {
- return
- }
- _, errs = ctx.ResolveDependencies(config)
- if errored(t, tc.description, errs) {
- return
- }
-
- checkDir := dir
- if tc.dir != "" {
- checkDir = tc.dir
- }
- codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
- bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
- if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
- t.Errorf("%s: Expected %d bazel target, got %d", tc.description, expectedCount, actualCount)
- } else {
- for i, target := range bazelTargets {
- if w, g := tc.expectedBazelTargets[i], target.content; w != g {
- t.Errorf(
- "%s: Expected generated Bazel target to be '%s', got '%s'",
- tc.description,
- w,
- g,
- )
- }
- }
- }
-}
-
func TestCcLibrarySimple(t *testing.T) {
runCcLibraryTestCase(t, bp2buildTestCase{
description: "cc_library - simple example",
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
index 712d0bd..ea2c10a 100644
--- a/bp2build/cc_library_headers_conversion_test.go
+++ b/bp2build/cc_library_headers_conversion_test.go
@@ -40,17 +40,6 @@
}`
)
-type bp2buildTestCase struct {
- description string
- moduleTypeUnderTest string
- moduleTypeUnderTestFactory android.ModuleFactory
- moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
- blueprint string
- expectedBazelTargets []string
- filesystem map[string]string
- dir string
-}
-
func TestCcLibraryHeadersLoadStatement(t *testing.T) {
testCases := []struct {
bazelTargets BazelTargets
diff --git a/bp2build/python_binary_conversion_test.go b/bp2build/python_binary_conversion_test.go
index 7bedf71..6f6fc11 100644
--- a/bp2build/python_binary_conversion_test.go
+++ b/bp2build/python_binary_conversion_test.go
@@ -7,13 +7,15 @@
"android/soong/python"
)
-func runPythonTestCase(t *testing.T, tc bp2buildTestCase) {
- t.Helper()
- runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+func runBp2BuildTestCaseWithLibs(t *testing.T, tc bp2buildTestCase) {
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
+ ctx.RegisterModuleType("python_library_host", python.PythonLibraryHostFactory)
+ }, tc)
}
func TestPythonBinaryHostSimple(t *testing.T) {
- runPythonTestCase(t, bp2buildTestCase{
+ runBp2BuildTestCaseWithLibs(t, bp2buildTestCase{
description: "simple python_binary_host converts to a native py_binary",
moduleTypeUnderTest: "python_binary_host",
moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
@@ -31,12 +33,18 @@
srcs: ["**/*.py"],
exclude_srcs: ["b/e.py"],
data: ["files/data.txt",],
+ libs: ["bar"],
bazel_module: { bp2build_available: true },
}
-`,
+ python_library_host {
+ name: "bar",
+ srcs: ["b/e.py"],
+ bazel_module: { bp2build_available: true },
+ }`,
expectedBazelTargets: []string{`py_binary(
name = "foo",
data = ["files/data.txt"],
+ deps = [":bar"],
main = "a.py",
srcs = [
"a.py",
@@ -49,7 +57,7 @@
}
func TestPythonBinaryHostPy2(t *testing.T) {
- runPythonTestCase(t, bp2buildTestCase{
+ runBp2BuildTestCaseSimple(t, bp2buildTestCase{
description: "py2 python_binary_host",
moduleTypeUnderTest: "python_binary_host",
moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
@@ -79,7 +87,7 @@
}
func TestPythonBinaryHostPy3(t *testing.T) {
- runPythonTestCase(t, bp2buildTestCase{
+ runBp2BuildTestCaseSimple(t, bp2buildTestCase{
description: "py3 python_binary_host",
moduleTypeUnderTest: "python_binary_host",
moduleTypeUnderTestFactory: python.PythonBinaryHostFactory,
diff --git a/bp2build/python_library_conversion_test.go b/bp2build/python_library_conversion_test.go
new file mode 100644
index 0000000..b6f45e5
--- /dev/null
+++ b/bp2build/python_library_conversion_test.go
@@ -0,0 +1,156 @@
+package bp2build
+
+import (
+ "fmt"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/python"
+)
+
+// TODO(alexmarquez): Should be lifted into a generic Bp2Build file
+type PythonLibBp2Build func(ctx android.TopDownMutatorContext)
+
+func TestPythonLibrary(t *testing.T) {
+ testPythonLib(t, "python_library",
+ python.PythonLibraryFactory, python.PythonLibraryBp2Build,
+ func(ctx android.RegistrationContext) {})
+}
+
+func TestPythonLibraryHost(t *testing.T) {
+ testPythonLib(t, "python_library_host",
+ python.PythonLibraryHostFactory, python.PythonLibraryHostBp2Build,
+ func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("python_library", python.PythonLibraryFactory)
+ })
+}
+
+func testPythonLib(t *testing.T, modType string,
+ factory android.ModuleFactory, mutator PythonLibBp2Build,
+ registration func(ctx android.RegistrationContext)) {
+ t.Helper()
+ // Simple
+ runBp2BuildTestCase(t, registration, bp2buildTestCase{
+ description: fmt.Sprintf("simple %s converts to a native py_library", modType),
+ moduleTypeUnderTest: modType,
+ moduleTypeUnderTestFactory: factory,
+ moduleTypeUnderTestBp2BuildMutator: mutator,
+ filesystem: map[string]string{
+ "a.py": "",
+ "b/c.py": "",
+ "b/d.py": "",
+ "b/e.py": "",
+ "files/data.txt": "",
+ },
+ blueprint: fmt.Sprintf(`%s {
+ name: "foo",
+ srcs: ["**/*.py"],
+ exclude_srcs: ["b/e.py"],
+ data: ["files/data.txt",],
+ libs: ["bar"],
+ bazel_module: { bp2build_available: true },
+}
+ python_library {
+ name: "bar",
+ srcs: ["b/e.py"],
+ bazel_module: { bp2build_available: false },
+ }`, modType),
+ expectedBazelTargets: []string{`py_library(
+ name = "foo",
+ data = ["files/data.txt"],
+ deps = [":bar"],
+ srcs = [
+ "a.py",
+ "b/c.py",
+ "b/d.py",
+ ],
+ srcs_version = "PY3",
+)`,
+ },
+ })
+
+ // PY2
+ runBp2BuildTestCaseSimple(t, bp2buildTestCase{
+ description: fmt.Sprintf("py2 %s converts to a native py_library", modType),
+ moduleTypeUnderTest: modType,
+ moduleTypeUnderTestFactory: factory,
+ moduleTypeUnderTestBp2BuildMutator: mutator,
+ blueprint: fmt.Sprintf(`%s {
+ name: "foo",
+ srcs: ["a.py"],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+
+ bazel_module: { bp2build_available: true },
+}`, modType),
+ expectedBazelTargets: []string{`py_library(
+ name = "foo",
+ srcs = ["a.py"],
+ srcs_version = "PY2",
+)`,
+ },
+ })
+
+ // PY3
+ runBp2BuildTestCaseSimple(t, bp2buildTestCase{
+ description: fmt.Sprintf("py3 %s converts to a native py_library", modType),
+ moduleTypeUnderTest: modType,
+ moduleTypeUnderTestFactory: factory,
+ moduleTypeUnderTestBp2BuildMutator: mutator,
+ blueprint: fmt.Sprintf(`%s {
+ name: "foo",
+ srcs: ["a.py"],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ },
+ },
+
+ bazel_module: { bp2build_available: true },
+}`, modType),
+ expectedBazelTargets: []string{`py_library(
+ name = "foo",
+ srcs = ["a.py"],
+ srcs_version = "PY3",
+)`,
+ },
+ })
+
+ // Both
+ runBp2BuildTestCaseSimple(t, bp2buildTestCase{
+ description: fmt.Sprintf("py2&3 %s converts to a native py_library", modType),
+ moduleTypeUnderTest: modType,
+ moduleTypeUnderTestFactory: factory,
+ moduleTypeUnderTestBp2BuildMutator: mutator,
+ blueprint: fmt.Sprintf(`%s {
+ name: "foo",
+ srcs: ["a.py"],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: true,
+ },
+ },
+
+ bazel_module: { bp2build_available: true },
+}`, modType),
+ expectedBazelTargets: []string{
+ // srcs_version is PY2ANDPY3 by default.
+ `py_library(
+ name = "foo",
+ srcs = ["a.py"],
+)`,
+ },
+ })
+}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 266b817..a549a93 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -1,6 +1,26 @@
+// Copyright 2021 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 bp2build
+/*
+For shareable/common bp2build testing functionality and dumping ground for
+specific-but-shared functionality among tests in package
+*/
+
import (
+ "strings"
"testing"
"android/soong/android"
@@ -16,6 +36,87 @@
buildDir string
)
+func errored(t *testing.T, desc string, errs []error) bool {
+ t.Helper()
+ if len(errs) > 0 {
+ for _, err := range errs {
+ t.Errorf("%s: %s", desc, err)
+ }
+ return true
+ }
+ return false
+}
+
+func runBp2BuildTestCaseSimple(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, func(ctx android.RegistrationContext) {}, tc)
+}
+
+type bp2buildTestCase struct {
+ description string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+ blueprint string
+ expectedBazelTargets []string
+ filesystem map[string]string
+ dir string
+}
+
+func runBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc bp2buildTestCase) {
+ t.Helper()
+ dir := "."
+ filesystem := make(map[string][]byte)
+ toParse := []string{
+ "Android.bp",
+ }
+ for f, content := range tc.filesystem {
+ if strings.HasSuffix(f, "Android.bp") {
+ toParse = append(toParse, f)
+ }
+ filesystem[f] = []byte(content)
+ }
+ config := android.TestConfig(buildDir, nil, tc.blueprint, filesystem)
+ ctx := android.NewTestContext(config)
+
+ registerModuleTypes(ctx)
+ ctx.RegisterModuleType(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestFactory)
+ ctx.RegisterBp2BuildConfig(bp2buildConfig)
+ ctx.RegisterBp2BuildMutator(tc.moduleTypeUnderTest, tc.moduleTypeUnderTestBp2BuildMutator)
+ ctx.RegisterForBazelConversion()
+
+ _, errs := ctx.ParseFileList(dir, toParse)
+ if errored(t, tc.description, errs) {
+ return
+ }
+ _, errs = ctx.ResolveDependencies(config)
+ if errored(t, tc.description, errs) {
+ return
+ }
+
+ checkDir := dir
+ if tc.dir != "" {
+ checkDir = tc.dir
+ }
+ codegenCtx := NewCodegenContext(config, *ctx.Context, Bp2Build)
+ bazelTargets := generateBazelTargetsForDir(codegenCtx, checkDir)
+ if actualCount, expectedCount := len(bazelTargets), len(tc.expectedBazelTargets); actualCount != expectedCount {
+ t.Errorf("%s: Expected %d bazel target, got %d; %v",
+ tc.description, expectedCount, actualCount, bazelTargets)
+ } else {
+ for i, target := range bazelTargets {
+ if w, g := tc.expectedBazelTargets[i], target.content; w != g {
+ t.Errorf(
+ "%s: Expected generated Bazel target to be '%s', got '%s'",
+ tc.description,
+ w,
+ g,
+ )
+ }
+ }
+ }
+}
+
type nestedProps struct {
Nested_prop string
}
@@ -44,17 +145,6 @@
props customProps
}
-func errored(t *testing.T, desc string, errs []error) bool {
- t.Helper()
- if len(errs) > 0 {
- for _, err := range errs {
- t.Errorf("%s: %s", desc, err)
- }
- return true
- }
- return false
-}
-
// OutputFiles is needed because some instances of this module use dist with a
// tag property which requires the module implements OutputFileProducer.
func (m *customModule) OutputFiles(tag string) (android.Paths, error) {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index e95d5a7..cd52363 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -294,6 +294,9 @@
if library.buildStubs() {
entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
}
+ if library.apiListCoverageXmlPath.String() != "" {
+ entries.SetString("SOONG_CC_API_XML", "$(SOONG_CC_API_XML) "+library.apiListCoverageXmlPath.String())
+ }
})
}
// If a library providing a stub is included in an APEX, the private APIs of the library
diff --git a/cc/binary.go b/cc/binary.go
index 763d2b9..b423c50 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -156,6 +156,10 @@
}
}
+ if binary.static() {
+ deps.StaticLibs = append(deps.StaticLibs, deps.SystemSharedLibs...)
+ }
+
if ctx.toolchain().Bionic() {
if binary.static() {
if ctx.selectedStl() == "libc++_static" {
@@ -208,7 +212,7 @@
func (binary *binaryDecorator) linkerInit(ctx BaseModuleContext) {
binary.baseLinker.linkerInit(ctx)
- if !ctx.toolchain().Bionic() {
+ if !ctx.toolchain().Bionic() && !ctx.toolchain().Musl() {
if ctx.Os() == android.Linux {
// Unless explicitly specified otherwise, host static binaries are built with -static
// if HostStaticBinaries is true for the product configuration.
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index ebf89ea..71e0cd8 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -38,16 +38,16 @@
android.SdkMemberTypeBase
}
-func (mt *binarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- targets := mctx.MultiTargets()
+func (mt *binarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ targets := ctx.MultiTargets()
for _, bin := range names {
for _, target := range targets {
variations := target.Variations()
- if mctx.Device() {
+ if ctx.Device() {
variations = append(variations,
blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
}
- mctx.AddFarVariationDependencies(variations, dependencyTag, bin)
+ ctx.AddFarVariationDependencies(variations, dependencyTag, bin)
}
}
}
diff --git a/cc/builder.go b/cc/builder.go
index 0e6d0b7..748377b 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -386,9 +386,6 @@
systemIncludeFlags string
- // True if static libraries should be grouped (using `-Wl,--start-group` and `-Wl,--end-group`).
- groupStaticLibs bool
-
proto android.ProtoFlags
protoC bool // If true, compile protos as `.c` files. Otherwise, output as `.cc`.
protoOptionsFile bool // If true, output a proto options file.
@@ -648,7 +645,7 @@
OrderOnly: pathDeps,
Args: map[string]string{
"cFlags": moduleToolingFlags,
- "tidyFlags": flags.tidyFlags,
+ "tidyFlags": config.TidyFlagsForSrcFile(srcFile, flags.tidyFlags),
},
})
}
@@ -754,13 +751,7 @@
}
}
- if flags.groupStaticLibs && !ctx.Darwin() && len(staticLibs) > 0 {
- libFlagsList = append(libFlagsList, "-Wl,--start-group")
- }
libFlagsList = append(libFlagsList, staticLibs.Strings()...)
- if flags.groupStaticLibs && !ctx.Darwin() && len(staticLibs) > 0 {
- libFlagsList = append(libFlagsList, "-Wl,--end-group")
- }
if groupLate && !ctx.Darwin() && len(lateStaticLibs) > 0 {
libFlagsList = append(libFlagsList, "-Wl,--start-group")
diff --git a/cc/cc.go b/cc/cc.go
index 243f0a5..b0c0299 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -217,8 +217,6 @@
// True if .s files should be processed with the c preprocessor.
AssemblerWithCpp bool
- // True if static libraries should be grouped (using `-Wl,--start-group` and `-Wl,--end-group`).
- GroupStaticLibs bool
proto android.ProtoFlags
protoC bool // Whether to use C instead of C++
@@ -975,16 +973,17 @@
return String(c.Properties.Min_sdk_version)
}
-func (c *Module) SplitPerApiLevel() bool {
- if !c.canUseSdk() {
- return false
- }
+func (c *Module) isCrt() bool {
if linker, ok := c.linker.(*objectLinker); ok {
return linker.isCrt()
}
return false
}
+func (c *Module) SplitPerApiLevel() bool {
+ return c.canUseSdk() && c.isCrt()
+}
+
func (c *Module) AlwaysSdk() bool {
return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only)
}
@@ -1446,12 +1445,20 @@
// create versioned variants for. For example, if min_sdk_version is 16, then sdk variant of
// the crt object has local variants of 16, 17, ..., up to the latest version. sdk_version
// and min_sdk_version properties of the variants are set to the corresponding version
- // numbers. However, the platform (non-sdk) variant of the crt object is left untouched.
- // min_sdk_version: 16 doesn't actually mean that the platform variant has to support such
- // an old version. Since the variant is for the platform, it's preferred to target the
- // latest version.
- if ctx.mod.SplitPerApiLevel() && !ctx.isSdkVariant() {
- ver = strconv.Itoa(android.FutureApiLevelInt)
+ // numbers. However, the non-sdk variant (for apex or platform) of the crt object is left
+ // untouched. min_sdk_version: 16 doesn't actually mean that the non-sdk variant has to
+ // support such an old version. The version is set to the later version in case when the
+ // non-sdk variant is for the platform, or the min_sdk_version of the containing APEX if
+ // it's for an APEX.
+ if ctx.mod.isCrt() && !ctx.isSdkVariant() {
+ if ctx.isForPlatform() {
+ ver = strconv.Itoa(android.FutureApiLevelInt)
+ } else { // for apex
+ ver = ctx.apexSdkVersion().String()
+ if ver == "" { // in case when min_sdk_version was not set by the APEX
+ ver = ctx.sdkVersion()
+ }
+ }
}
// Also make sure that minSdkVersion is not greater than sdkVersion, if they are both numbers
diff --git a/cc/cmakelists.go b/cc/cmakelists.go
index 04536fc..ad130ba 100644
--- a/cc/cmakelists.go
+++ b/cc/cmakelists.go
@@ -316,7 +316,7 @@
if strings.HasPrefix(parameter, "--sysroot") {
return systemRoot
}
- if strings.HasPrefix(parameter, "-fsanitize-blacklist") {
+ if strings.HasPrefix(parameter, "-fsanitize-ignorelist") {
return relativeFilePathFlag
}
if strings.HasPrefix(parameter, "-fprofile-sample-use") {
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index c4563e2..cf13503 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -106,6 +106,7 @@
const tidyDefault = "${config.TidyDefaultGlobalChecks}"
const tidyExternalVendor = "${config.TidyExternalVendorChecks}"
+const tidyDefaultNoAnalyzer = "${config.TidyDefaultGlobalChecks},-clang-analyzer-*"
// This is a map of local path prefixes to the set of default clang-tidy checks
// to be used.
@@ -139,3 +140,17 @@
}
return tidyDefault
}
+
+func TidyFlagsForSrcFile(srcFile android.Path, flags string) string {
+ // Disable clang-analyzer-* checks globally for generated source files
+ // because some of them are too huge. Local .bp files can add wanted
+ // clang-analyzer checks through the tidy_checks property.
+ // Need to do this patch per source file, because some modules
+ // have both generated and organic source files.
+ if _, ok := srcFile.(android.WritablePath); ok {
+ if strings.Contains(flags, tidyDefault) {
+ return strings.ReplaceAll(flags, tidyDefault, tidyDefaultNoAnalyzer)
+ }
+ }
+ return flags
+}
diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go
index e7fcfed..ac5d5f7 100644
--- a/cc/config/x86_linux_host.go
+++ b/cc/config/x86_linux_host.go
@@ -45,6 +45,7 @@
linuxMuslCflags = []string{
"-D_LIBCPP_HAS_MUSL_LIBC",
+ "-DANDROID_HOST_MUSL",
"-nostdlibinc",
}
@@ -106,7 +107,7 @@
"util",
}, "-l")
- muslCrtBeginStaticBinary, muslCrtEndStaticBinary = []string{"libc_musl_crtbegin_static"}, []string{"crtend_android"}
+ muslCrtBeginStaticBinary, muslCrtEndStaticBinary = []string{"libc_musl_crtbegin_static"}, []string{"libc_musl_crtend"}
muslCrtBeginSharedBinary, muslCrtEndSharedBinary = []string{"libc_musl_crtbegin_dynamic", "musl_linker_script"}, []string{"libc_musl_crtend"}
muslCrtBeginSharedLibrary, muslCrtEndSharedLibrary = []string{"libc_musl_crtbegin_so"}, []string{"libc_musl_crtend_so"}
diff --git a/cc/coverage.go b/cc/coverage.go
index baf4226..8dd2db1 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -244,3 +244,19 @@
m[1].(Coverage).EnableCoverageIfNeeded()
}
}
+
+func parseSymbolFileForAPICoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath {
+ apiLevelsJson := android.GetApiLevelsJson(ctx)
+ symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
+ outputFile := ctx.baseModuleName() + ".xml"
+ parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFile)
+ rule := android.NewRuleBuilder(pctx, ctx)
+ rule.Command().
+ BuiltTool("ndk_api_coverage_parser").
+ Input(symbolFilePath).
+ Output(parsedApiCoveragePath).
+ Implicit(apiLevelsJson).
+ FlagWithArg("--api-map ", apiLevelsJson.String())
+ rule.Build("native_library_api_list", "Generate native API list based on symbol files for coverage measurement")
+ return parsedApiCoveragePath
+}
diff --git a/cc/fuzz.go b/cc/fuzz.go
index fbef12b..83f0037 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -123,7 +123,7 @@
// that should be installed in the fuzz target output directories. This function
// returns true, unless:
// - The module is not an installable shared library, or
-// - The module is a header, stub, or vendor-linked library, or
+// - The module is a header or stub, or
// - The module is a prebuilt and its source is available, or
// - The module is a versioned member of an SDK snapshot.
func isValidSharedDependency(dependency android.Module) bool {
@@ -141,11 +141,6 @@
return false
}
- if linkable.UseVndk() {
- // Discard vendor linked libraries.
- return false
- }
-
if lib := moduleLibraryInterface(dependency); lib != nil && lib.buildStubs() && linkable.CcLibrary() {
// Discard stubs libs (only CCLibrary variants). Prebuilt libraries should not
// be excluded on the basis of they're not CCLibrary()'s.
diff --git a/cc/library.go b/cc/library.go
index 1526f81..196116b 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -536,6 +536,8 @@
*baseInstaller
collectedSnapshotHeaders android.Paths
+
+ apiListCoverageXmlPath android.ModuleOutPath
}
type ccLibraryBazelHandler struct {
@@ -951,6 +953,12 @@
objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
library.versionScriptPath = android.OptionalPathForPath(
nativeAbiResult.versionScript)
+
+ // Parse symbol file to get API list for coverage
+ if library.stubsVersion() == "current" && ctx.PrimaryArch() {
+ library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
+ }
+
return objs
}
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 9010a1a..1866ff3 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -74,8 +74,8 @@
linkTypes []string
}
-func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- targets := mctx.MultiTargets()
+func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ targets := ctx.MultiTargets()
for _, lib := range names {
for _, target := range targets {
name, version := StubsLibNameAndVersion(lib)
@@ -83,21 +83,21 @@
version = "latest"
}
variations := target.Variations()
- if mctx.Device() {
+ if ctx.Device() {
variations = append(variations,
blueprint.Variation{Mutator: "image", Variation: android.CoreVariation})
}
if mt.linkTypes == nil {
- mctx.AddFarVariationDependencies(variations, dependencyTag, name)
+ ctx.AddFarVariationDependencies(variations, dependencyTag, name)
} else {
for _, linkType := range mt.linkTypes {
libVariations := append(variations,
blueprint.Variation{Mutator: "link", Variation: linkType})
- if mctx.Device() && linkType == "shared" {
+ if ctx.Device() && linkType == "shared" {
libVariations = append(libVariations,
blueprint.Variation{Mutator: "version", Variation: version})
}
- mctx.AddFarVariationDependencies(libVariations, dependencyTag, name)
+ ctx.AddFarVariationDependencies(libVariations, dependencyTag, name)
}
}
}
diff --git a/cc/linker.go b/cc/linker.go
index 7c710d7..0d612b5 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -86,8 +86,7 @@
// compiling crt or libc.
Nocrt *bool `android:"arch_variant"`
- // group static libraries. This can resolve missing symbols issues with interdependencies
- // between static libraries, but it is generally better to order them correctly instead.
+ // deprecated and ignored because lld makes it unnecessary. See b/189475744.
Group_static_libs *bool `android:"arch_variant"`
// list of modules that should be installed with this module. This is similar to 'required'
@@ -95,6 +94,9 @@
// vendor variants and this module uses VNDK.
Runtime_libs []string `android:"arch_variant"`
+ // list of runtime libs that should not be installed along with this module.
+ Exclude_runtime_libs []string `android:"arch_variant"`
+
Target struct {
Vendor, Product struct {
// list of shared libs that only should be used to build vendor or
@@ -121,8 +123,8 @@
// product variant of the C/C++ module.
Exclude_header_libs []string
- // list of runtime libs that should not be installed along with
- // vendor or variant of the C/C++ module.
+ // list of runtime libs that should not be installed along with the
+ // vendor or product variant of the C/C++ module.
Exclude_runtime_libs []string
// version script for vendor or product variant
@@ -148,6 +150,10 @@
// list of header libs that should not be used to build the recovery variant
// of the C/C++ module.
Exclude_header_libs []string
+
+ // list of runtime libs that should not be installed along with the
+ // recovery variant of the C/C++ module.
+ Exclude_runtime_libs []string
}
Ramdisk struct {
// list of static libs that only should be used to build the recovery
@@ -161,6 +167,10 @@
// list of static libs that should not be used to build
// the ramdisk variant of the C/C++ module.
Exclude_static_libs []string
+
+ // list of runtime libs that should not be installed along with the
+ // ramdisk variant of the C/C++ module.
+ Exclude_runtime_libs []string
}
Vendor_ramdisk struct {
// list of shared libs that should not be used to build
@@ -170,6 +180,10 @@
// list of static libs that should not be used to build
// the vendor ramdisk variant of the C/C++ module.
Exclude_static_libs []string
+
+ // list of runtime libs that should not be installed along with the
+ // vendor ramdisk variant of the C/C++ module.
+ Exclude_runtime_libs []string
}
Platform struct {
// list of shared libs that should be use to build the platform variant
@@ -191,7 +205,7 @@
// the C/C++ module.
Exclude_shared_libs []string
- // list of static libs that should not be used to build the apex ramdisk
+ // list of static libs that should not be used to build the apex
// variant of the C/C++ module.
Exclude_static_libs []string
}
@@ -275,6 +289,7 @@
deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Exclude_shared_libs)
deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Exclude_static_libs)
+ deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Exclude_runtime_libs)
// Record the libraries that need to be excluded when building for APEX. Unlike other
// target.*.exclude_* properties, SharedLibs and StaticLibs are not modified here because
@@ -325,6 +340,7 @@
deps.ReexportHeaderLibHeaders = removeListFromList(deps.ReexportHeaderLibHeaders, linker.Properties.Target.Recovery.Exclude_header_libs)
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Recovery.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
+ deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Recovery.Exclude_runtime_libs)
}
if ctx.inRamdisk() {
@@ -334,6 +350,7 @@
deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Ramdisk.Exclude_static_libs)
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Ramdisk.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Ramdisk.Exclude_static_libs)
+ deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Ramdisk.Exclude_runtime_libs)
}
if ctx.inVendorRamdisk() {
@@ -342,6 +359,7 @@
deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+ deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_runtime_libs)
}
if !ctx.useSdk() {
@@ -524,10 +542,6 @@
flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ToolchainLdflags())
- if Bool(linker.Properties.Group_static_libs) {
- flags.GroupStaticLibs = true
- }
-
// Version_script is not needed when linking stubs lib where the version
// script is created from the symbol map file.
if !linker.dynamicProperties.BuildStubs {
diff --git a/cc/ndk_api_coverage_parser/__init__.py b/cc/ndk_api_coverage_parser/__init__.py
index 7817c78..8b9cd66 100755
--- a/cc/ndk_api_coverage_parser/__init__.py
+++ b/cc/ndk_api_coverage_parser/__init__.py
@@ -21,7 +21,12 @@
import sys
from xml.etree.ElementTree import Element, SubElement, tostring
-from symbolfile import ALL_ARCHITECTURES, FUTURE_API_LEVEL, MultiplyDefinedSymbolError, SymbolFileParser
+from symbolfile import (
+ ALL_ARCHITECTURES,
+ FUTURE_API_LEVEL,
+ MultiplyDefinedSymbolError,
+ SymbolFileParser,
+)
ROOT_ELEMENT_TAG = 'ndk-library'
@@ -63,6 +68,7 @@
class XmlGenerator(object):
"""Output generator that writes parsed symbol file to a xml file."""
+
def __init__(self, output_file):
self.output_file = output_file
@@ -74,10 +80,14 @@
continue
version_attributes = parse_tags(version.tags)
_, _, postfix = version.name.partition('_')
- is_platform = postfix == 'PRIVATE' or postfix == 'PLATFORM'
+ is_platform = postfix in ('PRIVATE' , 'PLATFORM')
is_deprecated = postfix == 'DEPRECATED'
- version_attributes.update({PLATFORM_ATTRIBUTE_KEY: str(is_platform)})
- version_attributes.update({DEPRECATED_ATTRIBUTE_KEY: str(is_deprecated)})
+ version_attributes.update(
+ {PLATFORM_ATTRIBUTE_KEY: str(is_platform)}
+ )
+ version_attributes.update(
+ {DEPRECATED_ATTRIBUTE_KEY: str(is_deprecated)}
+ )
for symbol in version.symbols:
if VARIABLE_TAG in symbol.tags:
continue
@@ -103,13 +113,20 @@
"""Parses and returns command line arguments."""
parser = argparse.ArgumentParser()
- parser.add_argument('symbol_file', type=os.path.realpath, help='Path to symbol file.')
parser.add_argument(
- 'output_file', type=os.path.realpath,
- help='The output parsed api coverage file.')
+ 'symbol_file', type=os.path.realpath, help='Path to symbol file.'
+ )
parser.add_argument(
- '--api-map', type=os.path.realpath, required=True,
- help='Path to the API level map JSON file.')
+ 'output_file',
+ type=os.path.realpath,
+ help='The output parsed api coverage file.',
+ )
+ parser.add_argument(
+ '--api-map',
+ type=os.path.realpath,
+ required=True,
+ help='Path to the API level map JSON file.',
+ )
return parser.parse_args()
@@ -122,13 +139,15 @@
with open(args.symbol_file) as symbol_file:
try:
- versions = SymbolFileParser(symbol_file, api_map, "", FUTURE_API_LEVEL,
- True, True).parse()
+ versions = SymbolFileParser(
+ symbol_file, api_map, "", FUTURE_API_LEVEL, True, True
+ ).parse()
except MultiplyDefinedSymbolError as ex:
sys.exit('{}: error: {}'.format(args.symbol_file, ex))
generator = XmlGenerator(args.output_file)
generator.write(versions)
+
if __name__ == '__main__':
main()
diff --git a/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py
index 3ec14c1..141059c 100644
--- a/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py
+++ b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py
@@ -50,10 +50,12 @@
return False
return all(etree_equal(c1, c2) for c1, c2 in zip(elem1, elem2))
-
+# pylint: disable=line-too-long
class ApiCoverageSymbolFileParserTest(unittest.TestCase):
def test_parse(self):
- input_file = io.StringIO(textwrap.dedent(u"""\
+ input_file = io.StringIO(
+ textwrap.dedent(
+ u"""\
LIBLOG { # introduced-arm64=24 introduced-x86=24 introduced-x86_64=24
global:
android_name_to_log_id; # apex llndk introduced=23
@@ -64,22 +66,28 @@
local:
*;
};
-
+
LIBLOG_PLATFORM {
android_fdtrack; # llndk
android_net; # introduced=23
};
-
+
LIBLOG_FOO { # var
android_var;
};
- """))
- parser = SymbolFileParser(input_file, {}, "", FUTURE_API_LEVEL, True, True)
+ """
+ )
+ )
+ parser = SymbolFileParser(
+ input_file, {}, "", FUTURE_API_LEVEL, True, True
+ )
generator = nparser.XmlGenerator(io.StringIO())
result = generator.convertToXml(parser.parse())
- expected = fromstring('<ndk-library><symbol apex="True" arch="" introduced="23" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_name_to_log_id" /><symbol arch="arm" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_log_id_to_name" /><symbol arch="" introduced-arm64="24" introduced-x86="23" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_assert" /><symbol arch="" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_buf_write" /><symbol arch="" is_deprecated="False" is_platform="True" llndk="True" name="android_fdtrack" /><symbol arch="" introduced="23" is_deprecated="False" is_platform="True" name="android_net" /></ndk-library>')
+ expected = fromstring(
+ '<ndk-library><symbol apex="True" arch="" introduced="23" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_name_to_log_id" /><symbol arch="arm" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_log_id_to_name" /><symbol arch="" introduced-arm64="24" introduced-x86="23" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_assert" /><symbol arch="" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_buf_write" /><symbol arch="" is_deprecated="False" is_platform="True" llndk="True" name="android_fdtrack" /><symbol arch="" introduced="23" is_deprecated="False" is_platform="True" name="android_net" /></ndk-library>'
+ )
self.assertTrue(etree_equal(expected, result))
-
+# pylint: enable=line-too-long
def main():
suite = unittest.TestLoader().loadTestsFromName(__name__)
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 63e8261..51cdddf 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -29,7 +29,6 @@
func init() {
pctx.HostBinToolVariable("ndkStubGenerator", "ndkstubgen")
- pctx.HostBinToolVariable("ndk_api_coverage_parser", "ndk_api_coverage_parser")
pctx.HostBinToolVariable("abidiff", "abidiff")
pctx.HostBinToolVariable("abitidy", "abitidy")
pctx.HostBinToolVariable("abidw", "abidw")
@@ -43,12 +42,6 @@
CommandDeps: []string{"$ndkStubGenerator"},
}, "arch", "apiLevel", "apiMap", "flags")
- parseNdkApiRule = pctx.AndroidStaticRule("parseNdkApiRule",
- blueprint.RuleParams{
- Command: "$ndk_api_coverage_parser $in $out --api-map $apiMap",
- CommandDeps: []string{"$ndk_api_coverage_parser"},
- }, "apiMap")
-
abidw = pctx.AndroidStaticRule("abidw",
blueprint.RuleParams{
Command: "$abidw --type-id-style hash --no-corpus-path " +
@@ -276,24 +269,6 @@
android.Paths{src}, nil, nil)
}
-func parseSymbolFileForCoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath {
- apiLevelsJson := android.GetApiLevelsJson(ctx)
- symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
- outputFileName := strings.Split(symbolFilePath.Base(), ".")[0]
- parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFileName+".xml")
- ctx.Build(pctx, android.BuildParams{
- Rule: parseNdkApiRule,
- Description: "parse ndk api symbol file for api coverage: " + symbolFilePath.Rel(),
- Outputs: []android.WritablePath{parsedApiCoveragePath},
- Input: symbolFilePath,
- Implicits: []android.Path{apiLevelsJson},
- Args: map[string]string{
- "apiMap": apiLevelsJson.String(),
- },
- })
- return parsedApiCoveragePath
-}
-
func (this *stubDecorator) findImplementationLibrary(ctx ModuleContext) android.Path {
dep := ctx.GetDirectDepWithTag(strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix),
stubImplementation)
@@ -454,7 +429,7 @@
}
}
if c.apiLevel.IsCurrent() && ctx.PrimaryArch() {
- c.parsedCoverageXmlPath = parseSymbolFileForCoverage(ctx, symbolFile)
+ c.parsedCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
}
return objs
}
diff --git a/cc/object_test.go b/cc/object_test.go
index 0e5508a..259a892 100644
--- a/cc/object_test.go
+++ b/cc/object_test.go
@@ -15,8 +15,9 @@
package cc
import (
- "android/soong/android"
"testing"
+
+ "android/soong/android"
)
func TestMinSdkVersionsOfCrtObjects(t *testing.T) {
@@ -27,24 +28,23 @@
crt: true,
stl: "none",
min_sdk_version: "28",
-
+ vendor_available: true,
}`)
- arch := "android_arm64_armv8-a"
- for _, v := range []string{"", "28", "29", "30", "current"} {
- var variant string
- // platform variant
- if v == "" {
- variant = arch
- } else {
- variant = arch + "_sdk_" + v
- }
- cflags := ctx.ModuleForTests("crt_foo", variant).Rule("cc").Args["cFlags"]
- vNum := v
- if v == "current" || v == "" {
- vNum = "10000"
- }
- expected := "-target aarch64-linux-android" + vNum + " "
+ variants := []struct {
+ variant string
+ num string
+ }{
+ {"android_arm64_armv8-a", "10000"},
+ {"android_arm64_armv8-a_sdk_28", "28"},
+ {"android_arm64_armv8-a_sdk_29", "29"},
+ {"android_arm64_armv8-a_sdk_30", "30"},
+ {"android_arm64_armv8-a_sdk_current", "10000"},
+ {"android_vendor.29_arm64_armv8-a", "29"},
+ }
+ for _, v := range variants {
+ cflags := ctx.ModuleForTests("crt_foo", v.variant).Rule("cc").Args["cFlags"]
+ expected := "-target aarch64-linux-android" + v.num + " "
android.AssertStringDoesContain(t, "cflag", cflags, expected)
}
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index dd15ae1..f6a9d5b 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -41,7 +41,6 @@
hwasanCflags = []string{"-fno-omit-frame-pointer", "-Wno-frame-larger-than=",
"-fsanitize-hwaddress-abi=platform",
- "-fno-experimental-new-pass-manager",
// The following improves debug location information
// availability at the cost of its accuracy. It increases
// the likelihood of a stack variable's frame offset
@@ -57,7 +56,7 @@
}
cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso",
- "-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blocklist.txt"}
+ "-fsanitize-ignorelist=external/compiler-rt/lib/cfi/cfi_blocklist.txt"}
// -flto and -fvisibility are required by clang when -fsanitize=cfi is
// used, but have no effect on assembly files
cfiAsflags = []string{"-flto", "-fvisibility=default"}
@@ -65,7 +64,7 @@
"-Wl,-plugin-opt,O1"}
cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map"
- intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blocklist.txt"}
+ intOverflowCflags = []string{"-fsanitize-ignorelist=build/soong/cc/config/integer_overflow_blocklist.txt"}
minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
"-fno-sanitize-recover=integer,undefined"}
@@ -261,7 +260,7 @@
// the first one
Recover []string
- // value to pass to -fsanitize-blacklist
+ // value to pass to -fsanitize-ignorelist
Blocklist *string
}
@@ -757,7 +756,7 @@
blocklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blocklist)
if blocklist.Valid() {
- flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-blacklist="+blocklist.String())
+ flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-ignorelist="+blocklist.String())
flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path())
}
diff --git a/cc/testing.go b/cc/testing.go
index 071f1ec..d0dca6b 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -375,26 +375,42 @@
cc_object {
name: "crtbegin_so",
defaults: ["crt_defaults"],
+ srcs: ["crtbegin_so.c"],
+ objs: ["crtbrand"],
}
cc_object {
name: "crtbegin_dynamic",
defaults: ["crt_defaults"],
+ srcs: ["crtbegin.c"],
+ objs: ["crtbrand"],
}
cc_object {
name: "crtbegin_static",
defaults: ["crt_defaults"],
+ srcs: ["crtbegin.c"],
+ objs: ["crtbrand"],
}
cc_object {
name: "crtend_so",
defaults: ["crt_defaults"],
+ srcs: ["crtend_so.c"],
+ objs: ["crtbrand"],
}
cc_object {
name: "crtend_android",
defaults: ["crt_defaults"],
+ srcs: ["crtend.c"],
+ objs: ["crtbrand"],
+ }
+
+ cc_object {
+ name: "crtbrand",
+ defaults: ["crt_defaults"],
+ srcs: ["crtbrand.c"],
}
cc_library {
@@ -585,6 +601,11 @@
"defaults/cc/common/libm.map.txt": nil,
"defaults/cc/common/ndk_libandroid_support": nil,
"defaults/cc/common/ndk_libc++_shared": nil,
+ "defaults/cc/common/crtbegin_so.c": nil,
+ "defaults/cc/common/crtbegin.c": nil,
+ "defaults/cc/common/crtend_so.c": nil,
+ "defaults/cc/common/crtend.c": nil,
+ "defaults/cc/common/crtbrand.c": nil,
}.AddToFixture(),
// Place the default cc test modules that are common to all platforms in a location that will not
diff --git a/cc/util.go b/cc/util.go
index 9bba876..88b0aba 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -91,7 +91,6 @@
systemIncludeFlags: strings.Join(in.SystemIncludeFlags, " "),
assemblerWithCpp: in.AssemblerWithCpp,
- groupStaticLibs: in.GroupStaticLibs,
proto: in.proto,
protoC: in.protoC,
diff --git a/cmd/multiproduct_kati/main.go b/cmd/multiproduct_kati/main.go
index 2846387..fa63b46 100644
--- a/cmd/multiproduct_kati/main.go
+++ b/cmd/multiproduct_kati/main.go
@@ -20,6 +20,7 @@
"flag"
"fmt"
"io"
+ "io/ioutil"
"log"
"os"
"os/exec"
@@ -76,6 +77,36 @@
return nil
}
+const errorLeadingLines = 20
+const errorTrailingLines = 20
+
+func errMsgFromLog(filename string) string {
+ if filename == "" {
+ return ""
+ }
+
+ data, err := ioutil.ReadFile(filename)
+ if err != nil {
+ return ""
+ }
+
+ lines := strings.Split(strings.TrimSpace(string(data)), "\n")
+ if len(lines) > errorLeadingLines+errorTrailingLines+1 {
+ lines[errorLeadingLines] = fmt.Sprintf("... skipping %d lines ...",
+ len(lines)-errorLeadingLines-errorTrailingLines)
+
+ lines = append(lines[:errorLeadingLines+1],
+ lines[len(lines)-errorTrailingLines:]...)
+ }
+ var buf strings.Builder
+ for _, line := range lines {
+ buf.WriteString("> ")
+ buf.WriteString(line)
+ buf.WriteString("\n")
+ }
+ return buf.String()
+}
+
// TODO(b/70370883): This tool uses a lot of open files -- over the default
// soft limit of 1024 on some systems. So bump up to the hard limit until I fix
// the algorithm.
@@ -170,6 +201,23 @@
}
}
+func outDirBase() string {
+ outDirBase := os.Getenv("OUT_DIR")
+ if outDirBase == "" {
+ return "out"
+ } else {
+ return outDirBase
+ }
+}
+
+func distDir(outDir string) string {
+ if distDir := os.Getenv("DIST_DIR"); distDir != "" {
+ return filepath.Clean(distDir)
+ } else {
+ return filepath.Join(outDir, "dist")
+ }
+}
+
func main() {
stdio := terminal.StdioImpl{}
@@ -177,6 +225,12 @@
log := logger.New(output)
defer log.Cleanup()
+ for _, v := range os.Environ() {
+ log.Println("Environment: " + v)
+ }
+
+ log.Printf("Argv: %v\n", os.Args)
+
flag.Parse()
_, cancel := context.WithCancel(context.Background())
@@ -208,13 +262,7 @@
if !*incremental {
name += "-" + time.Now().Format("20060102150405")
}
-
- outDirBase := os.Getenv("OUT_DIR")
- if outDirBase == "" {
- outDirBase = "out"
- }
-
- outputDir = filepath.Join(outDirBase, name)
+ outputDir = filepath.Join(outDirBase(), name)
}
log.Println("Output directory:", outputDir)
@@ -231,11 +279,13 @@
var configLogsDir string
if *alternateResultDir {
- configLogsDir = filepath.Join(outputDir, "dist/logs")
+ configLogsDir = filepath.Join(distDir(outDirBase()), "logs")
} else {
configLogsDir = outputDir
}
+ log.Println("Logs dir: " + configLogsDir)
+
os.MkdirAll(configLogsDir, 0777)
log.SetOutput(filepath.Join(configLogsDir, "soong.log"))
trace.SetOutput(filepath.Join(configLogsDir, "build.trace"))
@@ -348,10 +398,11 @@
FileArgs: []zip.FileArg{
{GlobDir: logsDir, SourcePrefixToStrip: logsDir},
},
- OutputFilePath: filepath.Join(outputDir, "dist/logs.zip"),
+ OutputFilePath: filepath.Join(distDir(outDirBase()), "logs.zip"),
NumParallelJobs: runtime.NumCPU(),
CompressionLevel: 5,
}
+ log.Printf("Logs zip: %v\n", args.OutputFilePath)
if err := zip.Zip(args); err != nil {
log.Fatalf("Error zipping logs: %v", err)
}
@@ -424,10 +475,6 @@
args = append(args, "--soong-only")
}
- if *alternateResultDir {
- args = append(args, "dist")
- }
-
cmd := exec.Command(mpctx.SoongUi, args...)
cmd.Stdout = consoleLogWriter
cmd.Stderr = consoleLogWriter
@@ -439,6 +486,11 @@
"TARGET_BUILD_APPS=",
"TARGET_BUILD_UNBUNDLED=")
+ if *alternateResultDir {
+ cmd.Env = append(cmd.Env,
+ "DIST_DIR="+filepath.Join(distDir(outDirBase()), "products/"+product))
+ }
+
action := &status.Action{
Description: product,
Outputs: []string{product},
@@ -459,9 +511,17 @@
}
}
}
+ var errOutput string
+ if err == nil {
+ errOutput = ""
+ } else {
+ errOutput = errMsgFromLog(consoleLogPath)
+ }
+
mpctx.Status.FinishAction(status.ActionResult{
Action: action,
Error: err,
+ Output: errOutput,
})
}
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 9f09224..703a875 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -16,7 +16,7 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-bootstrap_go_binary {
+blueprint_go_binary {
name: "soong_build",
deps: [
"blueprint",
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 8aea037..16a4e1a 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -25,6 +25,7 @@
"android/soong/bp2build"
"android/soong/shared"
+
"github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/deptools"
"github.com/google/blueprint/pathtools"
@@ -43,6 +44,7 @@
delveListen string
delvePath string
+ moduleGraphFile string
docFile string
bazelQueryViewDir string
bp2buildMarker string
@@ -56,30 +58,32 @@
flag.StringVar(&outDir, "out", "", "Soong output directory (usually $TOP/out/soong)")
flag.StringVar(&availableEnvFile, "available_env", "", "File containing available environment variables")
flag.StringVar(&usedEnvFile, "used_env", "", "File containing used environment variables")
+ flag.StringVar(&globFile, "globFile", "build-globs.ninja", "the Ninja file of globs to output")
+ flag.StringVar(&globListDir, "globListDir", "", "the directory containing the glob list files")
+ flag.StringVar(&cmdlineArgs.SoongOutDir, "b", ".", "the build output directory")
+ flag.StringVar(&cmdlineArgs.OutDir, "n", "", "the ninja builddir directory")
+ flag.StringVar(&cmdlineArgs.ModuleListFile, "l", "", "file that lists filepaths to parse")
// Debug flags
flag.StringVar(&delveListen, "delve_listen", "", "Delve port to listen on for debugging")
flag.StringVar(&delvePath, "delve_path", "", "Path to Delve. Only used if --delve_listen is set")
-
- // Flags representing various modes soong_build can run in
- flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
- flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
- flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
-
- flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
- flag.StringVar(&globFile, "globFile", "build-globs.ninja", "the Ninja file of globs to output")
- flag.StringVar(&globListDir, "globListDir", "", "the directory containing the glob list files")
- flag.StringVar(&cmdlineArgs.BuildDir, "b", ".", "the build output directory")
- flag.StringVar(&cmdlineArgs.NinjaBuildDir, "n", "", "the ninja builddir directory")
- flag.StringVar(&cmdlineArgs.DepFile, "d", "", "the dependency file to output")
flag.StringVar(&cmdlineArgs.Cpuprofile, "cpuprofile", "", "write cpu profile to file")
flag.StringVar(&cmdlineArgs.TraceFile, "trace", "", "write trace to file")
flag.StringVar(&cmdlineArgs.Memprofile, "memprofile", "", "write memory profile to file")
flag.BoolVar(&cmdlineArgs.NoGC, "nogc", false, "turn off GC for debugging")
+
+ // Flags representing various modes soong_build can run in
+ flag.StringVar(&moduleGraphFile, "module_graph_file", "", "JSON module graph file to output")
+ flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
+ flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
+ flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
+ flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
+ flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
+
+ // Flags that probably shouldn't be flags of soong_build but we haven't found
+ // the time to remove them yet
flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap")
flag.BoolVar(&cmdlineArgs.UseValidations, "use-validations", false, "use validations to depend on go tests")
- flag.StringVar(&cmdlineArgs.ModuleListFile, "l", "", "file that lists filepaths to parse")
- flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
}
func newNameResolver(config android.Config) *android.NameResolver {
@@ -146,14 +150,10 @@
ninjaDeps := bootstrap.RunBlueprint(secondArgs, secondCtx.Context, secondConfig)
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
- globListFiles := writeBuildGlobsNinjaFile(secondCtx.SrcDir(), configuration.BuildDir(), secondCtx.Globs, configuration)
+ globListFiles := writeBuildGlobsNinjaFile(secondCtx.SrcDir(), configuration.SoongOutDir(), secondCtx.Globs, configuration)
ninjaDeps = append(ninjaDeps, globListFiles...)
- err = deptools.WriteDepFile(shared.JoinPath(topDir, secondArgs.DepFile), secondArgs.OutFile, ninjaDeps)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", secondArgs.DepFile, err)
- os.Exit(1)
- }
+ writeDepFile(secondArgs.OutFile, ninjaDeps)
}
// Run the code-generation phase to convert BazelTargetModules to BUILD files.
@@ -177,7 +177,7 @@
}
func writeMetrics(configuration android.Config) {
- metricsFile := filepath.Join(configuration.BuildDir(), "soong_build_metrics.pb")
+ metricsFile := filepath.Join(configuration.SoongOutDir(), "soong_build_metrics.pb")
err := android.WriteMetrics(configuration, metricsFile)
if err != nil {
fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
@@ -185,8 +185,8 @@
}
}
-func writeJsonModuleGraph(configuration android.Config, ctx *android.Context, path string, extraNinjaDeps []string) {
- f, err := os.Create(path)
+func writeJsonModuleGraph(ctx *android.Context, path string) {
+ f, err := os.Create(shared.JoinPath(topDir, path))
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
@@ -194,7 +194,6 @@
defer f.Close()
ctx.Context.PrintJSONGraph(f)
- writeFakeNinjaFile(extraNinjaDeps, configuration.BuildDir())
}
func writeBuildGlobsNinjaFile(srcDir, buildDir string, globs func() pathtools.MultipleGlobResults, config interface{}) []string {
@@ -208,6 +207,15 @@
return bootstrap.GlobFileListFiles(globDir)
}
+func writeDepFile(outputFile string, ninjaDeps []string) {
+ depFile := shared.JoinPath(topDir, outputFile+".d")
+ err := deptools.WriteDepFile(depFile, outputFile, ninjaDeps)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", depFile, err)
+ os.Exit(1)
+ }
+}
+
// doChosenActivity runs Soong for a specific activity, like bp2build, queryview
// or the actual Soong build for the build.ninja file. Returns the top level
// output file of the specific activity.
@@ -215,10 +223,9 @@
bazelConversionRequested := bp2buildMarker != ""
mixedModeBuild := configuration.BazelContext.BazelEnabled()
generateQueryView := bazelQueryViewDir != ""
- jsonModuleFile := configuration.Getenv("SOONG_DUMP_JSON_MODULE_GRAPH")
blueprintArgs := cmdlineArgs
- prepareBuildActions := !generateQueryView && jsonModuleFile == ""
+ prepareBuildActions := !generateQueryView && moduleGraphFile == ""
if bazelConversionRequested {
// Run the alternate pipeline of bp2build mutators and singleton to convert
// Blueprint to BUILD files before everything else.
@@ -233,27 +240,24 @@
ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, ctx.Context, configuration)
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
- globListFiles := writeBuildGlobsNinjaFile(ctx.SrcDir(), configuration.BuildDir(), ctx.Globs, configuration)
+ globListFiles := writeBuildGlobsNinjaFile(ctx.SrcDir(), configuration.SoongOutDir(), ctx.Globs, configuration)
ninjaDeps = append(ninjaDeps, globListFiles...)
- err := deptools.WriteDepFile(shared.JoinPath(topDir, blueprintArgs.DepFile), blueprintArgs.OutFile, ninjaDeps)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", blueprintArgs.DepFile, err)
- os.Exit(1)
+ // Convert the Soong module graph into Bazel BUILD files.
+ if generateQueryView {
+ runQueryView(configuration, ctx)
+ return cmdlineArgs.OutFile // TODO: This is a lie
+ } else if moduleGraphFile != "" {
+ writeJsonModuleGraph(ctx, moduleGraphFile)
+ writeDepFile(moduleGraphFile, ninjaDeps)
+ return moduleGraphFile
+ } else {
+ // The actual output (build.ninja) was written in the RunBlueprint() call
+ // above
+ writeDepFile(cmdlineArgs.OutFile, ninjaDeps)
}
}
- // Convert the Soong module graph into Bazel BUILD files.
- if generateQueryView {
- runQueryView(configuration, ctx)
- return cmdlineArgs.OutFile // TODO: This is a lie
- }
-
- if jsonModuleFile != "" {
- writeJsonModuleGraph(configuration, ctx, jsonModuleFile, extraNinjaDeps)
- return cmdlineArgs.OutFile // TODO: This is a lie
- }
-
writeMetrics(configuration)
return cmdlineArgs.OutFile
}
@@ -307,7 +311,7 @@
if shared.IsDebugging() {
// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
// enabled even if it completed successfully.
- extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.BuildDir(), "always_rerun_for_delve"))
+ extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.SoongOutDir(), "always_rerun_for_delve"))
}
if docFile != "" {
@@ -348,29 +352,6 @@
touch(shared.JoinPath(topDir, finalOutputFile))
}
-// Workarounds to support running bp2build in a clean AOSP checkout with no
-// prior builds, and exiting early as soon as the BUILD files get generated,
-// therefore not creating build.ninja files that soong_ui and callers of
-// soong_build expects.
-//
-// These files are: build.ninja and build.ninja.d. Since Kati hasn't been
-// ran as well, and `nothing` is defined in a .mk file, there isn't a ninja
-// target called `nothing`, so we manually create it here.
-func writeFakeNinjaFile(extraNinjaDeps []string, buildDir string) {
- extraNinjaDepsString := strings.Join(extraNinjaDeps, " \\\n ")
-
- ninjaFileName := "build.ninja"
- ninjaFile := shared.JoinPath(topDir, buildDir, ninjaFileName)
- ninjaFileD := shared.JoinPath(topDir, buildDir, ninjaFileName+".d")
- // A workaround to create the 'nothing' ninja target so `m nothing` works,
- // since bp2build runs without Kati, and the 'nothing' target is declared in
- // a Makefile.
- ioutil.WriteFile(ninjaFile, []byte("build nothing: phony\n phony_output = true\n"), 0666)
- ioutil.WriteFile(ninjaFileD,
- []byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFile, extraNinjaDepsString)),
- 0666)
-}
-
func touch(path string) {
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
@@ -505,7 +486,7 @@
ninjaDeps := bootstrap.RunBlueprint(blueprintArgs, bp2buildCtx.Context, configuration)
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
- globListFiles := writeBuildGlobsNinjaFile(bp2buildCtx.SrcDir(), configuration.BuildDir(), bp2buildCtx.Globs, configuration)
+ globListFiles := writeBuildGlobsNinjaFile(bp2buildCtx.SrcDir(), configuration.SoongOutDir(), bp2buildCtx.Globs, configuration)
ninjaDeps = append(ninjaDeps, globListFiles...)
// Run the code-generation phase to convert BazelTargetModules to BUILD files
@@ -513,8 +494,8 @@
codegenContext := bp2build.NewCodegenContext(configuration, *bp2buildCtx, bp2build.Bp2Build)
metrics := bp2build.Codegen(codegenContext)
- generatedRoot := shared.JoinPath(configuration.BuildDir(), "bp2build")
- workspaceRoot := shared.JoinPath(configuration.BuildDir(), "workspace")
+ generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
+ workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
excludes := []string{
"bazel-bin",
@@ -524,8 +505,8 @@
"bazel-" + filepath.Base(topDir),
}
- if cmdlineArgs.NinjaBuildDir[0] != '/' {
- excludes = append(excludes, cmdlineArgs.NinjaBuildDir)
+ if cmdlineArgs.OutDir[0] != '/' {
+ excludes = append(excludes, cmdlineArgs.OutDir)
}
existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
@@ -550,12 +531,7 @@
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
- depFile := bp2buildMarker + ".d"
- err = deptools.WriteDepFile(shared.JoinPath(topDir, depFile), bp2buildMarker, ninjaDeps)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Cannot write depfile '%s': %s\n", depFile, err)
- os.Exit(1)
- }
+ writeDepFile(bp2buildMarker, ninjaDeps)
// Create an empty bp2build marker file.
touch(shared.JoinPath(topDir, bp2buildMarker))
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index ebb8959..1bdd040 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -196,6 +196,10 @@
// If the library is optional or required.
Optional bool
+ // If the library is implicitly infered by Soong (as opposed to explicitly added via `uses_libs`
+ // or `optional_uses_libs`.
+ Implicit bool
+
// On-host build path to the library dex file (used in dex2oat argument --class-loader-context).
Host android.Path
@@ -258,8 +262,9 @@
const AnySdkVersion int = android.FutureApiLevelInt
// Add class loader context for the given library to the map entry for the given SDK version.
-func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathContext, sdkVer int, lib string,
- optional bool, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) error {
+func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathContext, sdkVer int,
+ lib string, optional, implicit bool, hostPath, installPath android.Path,
+ nestedClcMap ClassLoaderContextMap) error {
// For prebuilts, library should have the same name as the source module.
lib = android.RemoveOptionalPrebuiltPrefix(lib)
@@ -308,6 +313,7 @@
clcMap[sdkVer] = append(clcMap[sdkVer], &ClassLoaderContext{
Name: lib,
Optional: optional,
+ Implicit: implicit,
Host: hostPath,
Device: devicePath,
Subcontexts: subcontexts,
@@ -320,9 +326,10 @@
// about paths). For the subset of libraries that are used in dexpreopt, their build/install paths
// are validated later before CLC is used (in validateClassLoaderContext).
func (clcMap ClassLoaderContextMap) AddContext(ctx android.ModuleInstallPathContext, sdkVer int,
- lib string, optional bool, hostPath, installPath android.Path, nestedClcMap ClassLoaderContextMap) {
+ lib string, optional, implicit bool, hostPath, installPath android.Path,
+ nestedClcMap ClassLoaderContextMap) {
- err := clcMap.addContext(ctx, sdkVer, lib, optional, hostPath, installPath, nestedClcMap)
+ err := clcMap.addContext(ctx, sdkVer, lib, optional, implicit, hostPath, installPath, nestedClcMap)
if err != nil {
ctx.ModuleErrorf(err.Error())
}
@@ -366,13 +373,15 @@
// included). This is the list of libraries that should be in the <uses-library> tags in the
// manifest. Some of them may be present in the source manifest, others are added by manifest_fixer.
// Required and optional libraries are in separate lists.
-func (clcMap ClassLoaderContextMap) UsesLibs() (required []string, optional []string) {
+func (clcMap ClassLoaderContextMap) usesLibs(implicit bool) (required []string, optional []string) {
if clcMap != nil {
clcs := clcMap[AnySdkVersion]
required = make([]string, 0, len(clcs))
optional = make([]string, 0, len(clcs))
for _, clc := range clcs {
- if clc.Optional {
+ if implicit && !clc.Implicit {
+ // Skip, this is an explicit library and we need only the implicit ones.
+ } else if clc.Optional {
optional = append(optional, clc.Name)
} else {
required = append(required, clc.Name)
@@ -382,6 +391,14 @@
return required, optional
}
+func (clcMap ClassLoaderContextMap) UsesLibs() ([]string, []string) {
+ return clcMap.usesLibs(false)
+}
+
+func (clcMap ClassLoaderContextMap) ImplicitUsesLibs() ([]string, []string) {
+ return clcMap.usesLibs(true)
+}
+
func (clcMap ClassLoaderContextMap) Dump() string {
jsonCLC := toJsonClassLoaderContext(clcMap)
bytes, err := json.MarshalIndent(jsonCLC, "", " ")
@@ -524,6 +541,8 @@
// the same as Soong representation except that SDK versions and paths are represented with strings.
type jsonClassLoaderContext struct {
Name string
+ Optional bool
+ Implicit bool
Host string
Device string
Subcontexts []*jsonClassLoaderContext
@@ -555,6 +574,8 @@
for _, clc := range jClcs {
clcs = append(clcs, &ClassLoaderContext{
Name: clc.Name,
+ Optional: clc.Optional,
+ Implicit: clc.Implicit,
Host: constructPath(ctx, clc.Host),
Device: clc.Device,
Subcontexts: fromJsonClassLoaderContextRec(ctx, clc.Subcontexts),
@@ -579,6 +600,8 @@
for i, clc := range clcs {
jClcs[i] = &jsonClassLoaderContext{
Name: clc.Name,
+ Optional: clc.Optional,
+ Implicit: clc.Implicit,
Host: clc.Host.String(),
Device: clc.Device,
Subcontexts: toJsonClassLoaderContextRec(clc.Subcontexts),
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index 0b7b546..d81ac2c 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -50,33 +50,34 @@
ctx := testContext()
optional := false
+ implicit := true
m := make(ClassLoaderContextMap)
- m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
- m.AddContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
- m.AddContext(ctx, AnySdkVersion, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
+ m.AddContext(ctx, AnySdkVersion, "a", optional, implicit, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ m.AddContext(ctx, AnySdkVersion, "b", optional, implicit, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
+ m.AddContext(ctx, AnySdkVersion, "c", optional, implicit, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
// Add some libraries with nested subcontexts.
m1 := make(ClassLoaderContextMap)
- m1.AddContext(ctx, AnySdkVersion, "a1", optional, buildPath(ctx, "a1"), installPath(ctx, "a1"), nil)
- m1.AddContext(ctx, AnySdkVersion, "b1", optional, buildPath(ctx, "b1"), installPath(ctx, "b1"), nil)
+ m1.AddContext(ctx, AnySdkVersion, "a1", optional, implicit, buildPath(ctx, "a1"), installPath(ctx, "a1"), nil)
+ m1.AddContext(ctx, AnySdkVersion, "b1", optional, implicit, buildPath(ctx, "b1"), installPath(ctx, "b1"), nil)
m2 := make(ClassLoaderContextMap)
- m2.AddContext(ctx, AnySdkVersion, "a2", optional, buildPath(ctx, "a2"), installPath(ctx, "a2"), nil)
- m2.AddContext(ctx, AnySdkVersion, "b2", optional, buildPath(ctx, "b2"), installPath(ctx, "b2"), nil)
- m2.AddContext(ctx, AnySdkVersion, "c2", optional, buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
+ m2.AddContext(ctx, AnySdkVersion, "a2", optional, implicit, buildPath(ctx, "a2"), installPath(ctx, "a2"), nil)
+ m2.AddContext(ctx, AnySdkVersion, "b2", optional, implicit, buildPath(ctx, "b2"), installPath(ctx, "b2"), nil)
+ m2.AddContext(ctx, AnySdkVersion, "c2", optional, implicit, buildPath(ctx, "c2"), installPath(ctx, "c2"), m1)
m3 := make(ClassLoaderContextMap)
- m3.AddContext(ctx, AnySdkVersion, "a3", optional, buildPath(ctx, "a3"), installPath(ctx, "a3"), nil)
- m3.AddContext(ctx, AnySdkVersion, "b3", optional, buildPath(ctx, "b3"), installPath(ctx, "b3"), nil)
+ m3.AddContext(ctx, AnySdkVersion, "a3", optional, implicit, buildPath(ctx, "a3"), installPath(ctx, "a3"), nil)
+ m3.AddContext(ctx, AnySdkVersion, "b3", optional, implicit, buildPath(ctx, "b3"), installPath(ctx, "b3"), nil)
- m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), m2)
+ m.AddContext(ctx, AnySdkVersion, "d", optional, implicit, buildPath(ctx, "d"), installPath(ctx, "d"), m2)
// When the same library is both in conditional and unconditional context, it should be removed
// from conditional context.
- m.AddContext(ctx, 42, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
- m.AddContext(ctx, AnySdkVersion, "f", optional, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
+ m.AddContext(ctx, 42, "f", optional, implicit, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
+ m.AddContext(ctx, AnySdkVersion, "f", optional, implicit, buildPath(ctx, "f"), installPath(ctx, "f"), nil)
// Merge map with implicit root library that is among toplevel contexts => does nothing.
m.AddContextMap(m1, "c")
@@ -85,12 +86,12 @@
m.AddContextMap(m3, "m_g")
// Compatibility libraries with unknown install paths get default paths.
- m.AddContext(ctx, 29, AndroidHidlManager, optional, buildPath(ctx, AndroidHidlManager), nil, nil)
- m.AddContext(ctx, 29, AndroidHidlBase, optional, buildPath(ctx, AndroidHidlBase), nil, nil)
+ m.AddContext(ctx, 29, AndroidHidlManager, optional, implicit, buildPath(ctx, AndroidHidlManager), nil, nil)
+ m.AddContext(ctx, 29, AndroidHidlBase, optional, implicit, buildPath(ctx, AndroidHidlBase), nil, nil)
// Add "android.test.mock" to conditional CLC, observe that is gets removed because it is only
// needed as a compatibility library if "android.test.runner" is in CLC as well.
- m.AddContext(ctx, 30, AndroidTestMock, optional, buildPath(ctx, AndroidTestMock), nil, nil)
+ m.AddContext(ctx, 30, AndroidTestMock, optional, implicit, buildPath(ctx, AndroidTestMock), nil, nil)
valid, validationError := validateClassLoaderContext(m)
@@ -164,11 +165,12 @@
func TestCLCJson(t *testing.T) {
ctx := testContext()
optional := false
+ implicit := true
m := make(ClassLoaderContextMap)
- m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
- m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
- m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
- m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
+ m.AddContext(ctx, 28, "a", optional, implicit, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ m.AddContext(ctx, 29, "b", optional, implicit, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
+ m.AddContext(ctx, 30, "c", optional, implicit, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
+ m.AddContext(ctx, AnySdkVersion, "d", optional, implicit, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
jsonCLC := toJsonClassLoaderContext(m)
restored := fromJsonClassLoaderContext(ctx, jsonCLC)
android.AssertIntEquals(t, "The size of the maps should be the same.", len(m), len(restored))
@@ -189,12 +191,13 @@
func testCLCUnknownPath(t *testing.T, whichPath string) {
ctx := testContext()
optional := false
+ implicit := true
m := make(ClassLoaderContextMap)
if whichPath == "build" {
- m.AddContext(ctx, AnySdkVersion, "a", optional, nil, nil, nil)
+ m.AddContext(ctx, AnySdkVersion, "a", optional, implicit, nil, nil, nil)
} else {
- m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), nil, nil)
+ m.AddContext(ctx, AnySdkVersion, "a", optional, implicit, buildPath(ctx, "a"), nil, nil)
}
// The library should be added to <uses-library> tags by the manifest_fixer.
@@ -229,10 +232,11 @@
func TestCLCNestedConditional(t *testing.T) {
ctx := testContext()
optional := false
+ implicit := true
m1 := make(ClassLoaderContextMap)
- m1.AddContext(ctx, 42, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ m1.AddContext(ctx, 42, "a", optional, implicit, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
m := make(ClassLoaderContextMap)
- err := m.addContext(ctx, AnySdkVersion, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), m1)
+ err := m.addContext(ctx, AnySdkVersion, "b", optional, implicit, buildPath(ctx, "b"), installPath(ctx, "b"), m1)
checkError(t, err, "nested class loader context shouldn't have conditional part")
}
@@ -241,11 +245,12 @@
func TestCLCSdkVersionOrder(t *testing.T) {
ctx := testContext()
optional := false
+ implicit := true
m := make(ClassLoaderContextMap)
- m.AddContext(ctx, 28, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
- m.AddContext(ctx, 29, "b", optional, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
- m.AddContext(ctx, 30, "c", optional, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
- m.AddContext(ctx, AnySdkVersion, "d", optional, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
+ m.AddContext(ctx, 28, "a", optional, implicit, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ m.AddContext(ctx, 29, "b", optional, implicit, buildPath(ctx, "b"), installPath(ctx, "b"), nil)
+ m.AddContext(ctx, 30, "c", optional, implicit, buildPath(ctx, "c"), installPath(ctx, "c"), nil)
+ m.AddContext(ctx, AnySdkVersion, "d", optional, implicit, buildPath(ctx, "d"), installPath(ctx, "d"), nil)
valid, validationError := validateClassLoaderContext(m)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 7a74506..de3666a 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -159,7 +159,7 @@
}
func constructPath(ctx android.PathContext, path string) android.Path {
- buildDirPrefix := ctx.Config().BuildDir() + "/"
+ buildDirPrefix := ctx.Config().SoongOutDir() + "/"
if path == "" {
return nil
} else if strings.HasPrefix(path, buildDirPrefix) {
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 4c6ae82..1401c75 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -430,11 +430,6 @@
}
}
- // Never enable on eng.
- if global.IsEng {
- debugInfo = false
- }
-
if debugInfo {
cmd.Flag("--generate-mini-debug-info")
} else {
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 29a8a39..73d807d 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -60,8 +60,8 @@
// https://source.android.com/devices/bootloader/partitions/vendor-boot-partitions
Vendor_boot *bool
- // Optional kernel commandline
- Cmdline *string `android:"arch_variant"`
+ // Optional kernel commandline arguments
+ Cmdline []string `android:"arch_variant"`
// File that contains bootconfig parameters. This can be set only when `vendor_boot` is true
// and `header_version` is greater than or equal to 4.
@@ -152,7 +152,7 @@
dtb := android.PathForModuleSrc(ctx, dtbName)
cmd.FlagWithInput("--dtb ", dtb)
- cmdline := proptools.String(b.properties.Cmdline)
+ cmdline := strings.Join(b.properties.Cmdline, " ")
if cmdline != "" {
flag := "--cmdline "
if vendor {
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 1f7234d..38065f1 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -71,7 +71,9 @@
args = append(args, "--use-embedded-dex")
}
- requiredUsesLibs, optionalUsesLibs := classLoaderContexts.UsesLibs()
+ // manifest_fixer should add only the implicit SDK libraries inferred by Soong, not those added
+ // explicitly via `uses_libs`/`optional_uses_libs`.
+ requiredUsesLibs, optionalUsesLibs := classLoaderContexts.ImplicitUsesLibs()
for _, usesLib := range requiredUsesLibs {
args = append(args, "--uses-library", usesLib)
}
diff --git a/java/app.go b/java/app.go
index e7661df..5104f07 100755
--- a/java/app.go
+++ b/java/app.go
@@ -1224,17 +1224,28 @@
func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) {
if !ctx.Config().UnbundledBuild() || ctx.Config().UnbundledBuildImage() {
- ctx.AddVariationDependencies(nil, usesLibReqTag, u.usesLibraryProperties.Uses_libs...)
- ctx.AddVariationDependencies(nil, usesLibOptTag, u.presentOptionalUsesLibs(ctx)...)
+ reqTag := makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false, false)
+ ctx.AddVariationDependencies(nil, reqTag, u.usesLibraryProperties.Uses_libs...)
+
+ optTag := makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true, false)
+ ctx.AddVariationDependencies(nil, optTag, u.presentOptionalUsesLibs(ctx)...)
+
// Only add these extra dependencies if the module depends on framework libs. This avoids
// creating a cyclic dependency:
// e.g. framework-res -> org.apache.http.legacy -> ... -> framework-res.
if hasFrameworkLibs {
- // Dexpreopt needs paths to the dex jars of these libraries in order to construct
- // class loader context for dex2oat. Add them as a dependency with a special tag.
- ctx.AddVariationDependencies(nil, usesLibCompat29ReqTag, dexpreopt.CompatUsesLibs29...)
- ctx.AddVariationDependencies(nil, usesLibCompat28OptTag, dexpreopt.OptionalCompatUsesLibs28...)
- ctx.AddVariationDependencies(nil, usesLibCompat30OptTag, dexpreopt.OptionalCompatUsesLibs30...)
+ // Add implicit <uses-library> dependencies on compatibility libraries. Some of them are
+ // optional, and some required --- this depends on the most common usage of the library
+ // and may be wrong for some apps (they need explicit `uses_libs`/`optional_uses_libs`).
+
+ compat28OptTag := makeUsesLibraryDependencyTag(28, true, true)
+ ctx.AddVariationDependencies(nil, compat28OptTag, dexpreopt.OptionalCompatUsesLibs28...)
+
+ compat29ReqTag := makeUsesLibraryDependencyTag(29, false, true)
+ ctx.AddVariationDependencies(nil, compat29ReqTag, dexpreopt.CompatUsesLibs29...)
+
+ compat30OptTag := makeUsesLibraryDependencyTag(30, true, true)
+ ctx.AddVariationDependencies(nil, compat30OptTag, dexpreopt.OptionalCompatUsesLibs30...)
}
}
}
@@ -1293,7 +1304,7 @@
replaceInList(u.usesLibraryProperties.Uses_libs, dep, libName)
replaceInList(u.usesLibraryProperties.Optional_uses_libs, dep, libName)
}
- clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional,
+ clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional, tag.implicit,
lib.DexJarBuildPath(), lib.DexJarInstallPath(), lib.ClassLoaderContexts())
} else if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{dep})
diff --git a/java/app_test.go b/java/app_test.go
index c14c65d..07439fc 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1737,7 +1737,7 @@
foo := result.ModuleForTests("foo", "android_common")
- outSoongDir := result.Config.BuildDir()
+ outSoongDir := result.Config.SoongOutDir()
outputs := foo.AllOutputs()
outputMap := make(map[string]bool)
@@ -2398,14 +2398,7 @@
expectManifestFixerArgs := `--extract-native-libs=true ` +
`--uses-library qux ` +
`--uses-library quuz ` +
- `--uses-library foo ` + // TODO(b/132357300): "foo" should not be passed to manifest_fixer
- `--uses-library com.non.sdk.lib ` + // TODO(b/132357300): "com.non.sdk.lib" should not be passed to manifest_fixer
- `--uses-library runtime-library ` +
- `--uses-library runtime-required-x ` + // TODO(b/132357300): "runtime-required-x" should not be passed to manifest_fixer
- `--uses-library runtime-required-y ` + // TODO(b/132357300): "runtime-required-y" should not be passed to manifest_fixer
- `--optional-uses-library bar ` + // TODO(b/132357300): "bar" should not be passed to manifest_fixer
- `--optional-uses-library runtime-optional-x ` + // TODO(b/132357300): "runtime-optional-x" should not be passed to manifest_fixer
- `--optional-uses-library runtime-optional-y` // TODO(b/132357300): "runtime-optional-y" should not be passed to manifest_fixer
+ `--uses-library runtime-library`
android.AssertStringEquals(t, "manifest_fixer args", expectManifestFixerArgs, actualManifestFixerArgs)
// Test that all libraries are verified (library order matters).
diff --git a/java/base.go b/java/base.go
index ea5b137..86022c3 100644
--- a/java/base.go
+++ b/java/base.go
@@ -606,10 +606,8 @@
if component, ok := dep.(SdkLibraryComponentDependency); ok {
if lib := component.OptionalSdkLibraryImplementation(); lib != nil {
// Add library as optional if it's one of the optional compatibility libs.
- tag := usesLibReqTag
- if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) {
- tag = usesLibOptTag
- }
+ optional := android.InList(*lib, dexpreopt.OptionalCompatUsesLibs)
+ tag := makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, optional, true)
ctx.AddVariationDependencies(nil, tag, *lib)
}
}
@@ -793,7 +791,7 @@
// Manually specify build directory in case it is not under the repo root.
// (javac doesn't seem to expand into symbolic links when searching for patch-module targets, so
// just adding a symlink under the root doesn't help.)
- patchPaths := []string{".", ctx.Config().BuildDir()}
+ patchPaths := []string{".", ctx.Config().SoongOutDir()}
// b/150878007
//
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index bb542c4..f7561b4 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -538,7 +538,7 @@
global := dexpreopt.GetGlobalConfig(ctx)
possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag)
- jars := global.ApexBootJars.Filter(possibleUpdatableModules)
+ jars, unknown := global.ApexBootJars.Filter(possibleUpdatableModules)
// TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths
// config. However, any test specific jars would not be present in ApexBootJars. Instead,
@@ -546,6 +546,12 @@
// This is an exception to support end-to-end test for SdkExtensions, until such support exists.
if android.InList("test_framework-sdkextensions", possibleUpdatableModules) {
jars = jars.Append("com.android.sdkext", "test_framework-sdkextensions")
+ } else if global.ApexBootJars.Len() != 0 && !android.IsModuleInVersionedSdk(ctx.Module()) {
+ unknown = android.RemoveListFromList(unknown, b.properties.Coverage.Contents)
+ _, unknown = android.RemoveFromList("core-icu4j", unknown)
+ if len(unknown) > 0 {
+ ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
+ }
}
return jars
}
@@ -712,8 +718,8 @@
android.SdkMemberTypeBase
}
-func (b *bootclasspathFragmentMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (b *bootclasspathFragmentMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (b *bootclasspathFragmentMemberType) IsInstance(module android.Module) bool {
diff --git a/java/core-libraries/Android.bp b/java/core-libraries/Android.bp
index 51d998a..b198c24 100644
--- a/java/core-libraries/Android.bp
+++ b/java/core-libraries/Android.bp
@@ -24,6 +24,10 @@
// core libraries.
//
// Don't use this directly, use "sdk_version: core_current".
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
java_library {
name: "core.current.stubs",
visibility: ["//visibility:public"],
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 1019b4c..946092c 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -500,7 +500,11 @@
dst := dstBootJarsByModule[name]
if src == nil {
- ctx.ModuleErrorf("module %s does not provide a dex boot jar", name)
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.ModuleErrorf("module %s does not provide a dex boot jar", name)
+ } else {
+ ctx.AddMissingDependencies([]string{name})
+ }
} else if dst == nil {
ctx.ModuleErrorf("module %s is not part of the boot configuration", name)
} else {
diff --git a/java/java.go b/java/java.go
index b46324f..1a052b4 100644
--- a/java/java.go
+++ b/java/java.go
@@ -248,15 +248,24 @@
type usesLibraryDependencyTag struct {
dependencyTag
- sdkVersion int // SDK version in which the library appared as a standalone library.
- optional bool // If the dependency is optional or required.
+
+ // SDK version in which the library appared as a standalone library.
+ sdkVersion int
+
+ // If the dependency is optional or required.
+ optional bool
+
+ // Whether this is an implicit dependency inferred by Soong, or an explicit one added via
+ // `uses_libs`/`optional_uses_libs` properties.
+ implicit bool
}
-func makeUsesLibraryDependencyTag(sdkVersion int, optional bool) usesLibraryDependencyTag {
+func makeUsesLibraryDependencyTag(sdkVersion int, optional bool, implicit bool) usesLibraryDependencyTag {
return usesLibraryDependencyTag{
dependencyTag: dependencyTag{name: fmt.Sprintf("uses-library-%d", sdkVersion)},
sdkVersion: sdkVersion,
optional: optional,
+ implicit: implicit,
}
}
@@ -285,11 +294,6 @@
syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"}
jniInstallTag = installDependencyTag{name: "jni install"}
binaryInstallTag = installDependencyTag{name: "binary install"}
- usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false)
- usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true)
- usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true)
- usesLibCompat29ReqTag = makeUsesLibraryDependencyTag(29, false)
- usesLibCompat30OptTag = makeUsesLibraryDependencyTag(30, true)
)
func IsLibDepTag(depTag blueprint.DependencyTag) bool {
@@ -570,8 +574,8 @@
copyEverythingToSnapshot = false
)
-func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (mt *librarySdkMemberType) IsInstance(module android.Module) bool {
@@ -871,8 +875,8 @@
android.SdkMemberTypeBase
}
-func (mt *testSdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (mt *testSdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (mt *testSdkMemberType) IsInstance(module android.Module) bool {
@@ -1813,8 +1817,10 @@
depTag := ctx.OtherModuleDependencyTag(depModule)
if depTag == libTag {
// Ok, propagate <uses-library> through non-static library dependencies.
- } else if tag, ok := depTag.(usesLibraryDependencyTag); ok && tag.sdkVersion == dexpreopt.AnySdkVersion {
- // Ok, propagate <uses-library> through non-compatibility <uses-library> dependencies.
+ } else if tag, ok := depTag.(usesLibraryDependencyTag); ok &&
+ tag.sdkVersion == dexpreopt.AnySdkVersion && tag.implicit {
+ // Ok, propagate <uses-library> through non-compatibility implicit <uses-library>
+ // dependencies.
} else if depTag == staticLibTag {
// Propagate <uses-library> through static library dependencies, unless it is a component
// library (such as stubs). Component libraries have a dependency on their SDK library,
@@ -1832,7 +1838,7 @@
// <uses_library> and should not be added to CLC, but the transitive <uses-library> dependencies
// from its CLC should be added to the current CLC.
if sdkLib != nil {
- clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, false,
+ clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, false, true,
dep.DexJarBuildPath(), dep.DexJarInstallPath(), dep.ClassLoaderContexts())
} else {
clcMap.AddContextMap(dep.ClassLoaderContexts(), depName)
diff --git a/java/java_test.go b/java/java_test.go
index b6780c2..8bb017f 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1183,7 +1183,7 @@
break
}
}
- if expected != android.StringPathRelativeToTop(ctx.Config().BuildDir(), got) {
+ if expected != android.StringPathRelativeToTop(ctx.Config().SoongOutDir(), got) {
t.Errorf("Unexpected patch-module flag for module %q - expected %q, but got %q", moduleName, expected, got)
}
}
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 712c2a2..0d8ebac 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -134,8 +134,8 @@
android.SdkMemberTypeBase
}
-func (b *compatConfigMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (b *compatConfigMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (b *compatConfigMemberType) IsInstance(module android.Module) bool {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index c50e077..ce8f179 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -2471,8 +2471,8 @@
android.SdkMemberTypeBase
}
-func (s *sdkLibrarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (s *sdkLibrarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool {
diff --git a/java/system_modules.go b/java/system_modules.go
index d0dc74a..fec8eba 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -245,8 +245,8 @@
android.SdkMemberTypeBase
}
-func (mt *systemModulesSdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
- mctx.AddVariationDependencies(nil, dependencyTag, names...)
+func (mt *systemModulesSdkMemberType) AddDependencies(ctx android.SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string) {
+ ctx.AddVariationDependencies(nil, dependencyTag, names...)
}
func (mt *systemModulesSdkMemberType) IsInstance(module android.Module) bool {
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 6c2a5b5..5311f62 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -107,7 +107,16 @@
global := dexpreopt.GetGlobalConfig(ctx)
possibleUpdatableModules := gatherPossibleApexModuleNamesAndStems(ctx, s.properties.Contents, systemServerClasspathFragmentContentDepTag)
- return global.ApexSystemServerJars.Filter(possibleUpdatableModules)
+ jars, unknown := global.ApexSystemServerJars.Filter(possibleUpdatableModules)
+ // TODO(satayev): remove geotz ssc_fragment, since geotz is not part of SSCP anymore.
+ _, unknown = android.RemoveFromList("geotz", unknown)
+
+ // For non test apexes, make sure that all contents are actually declared in make.
+ if global.ApexSystemServerJars.Len() > 0 && len(unknown) > 0 {
+ ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_UPDATABLE_SYSTEM_SERVER_JARS", unknown)
+ }
+
+ return jars
}
type systemServerClasspathFragmentContentDependencyTag struct {
diff --git a/mk2rbc/Android.bp b/mk2rbc/Android.bp
index 3ea3f7f..4fa3eb6 100644
--- a/mk2rbc/Android.bp
+++ b/mk2rbc/Android.bp
@@ -13,6 +13,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
blueprint_go_binary {
name: "mk2rbc",
srcs: ["cmd/mk2rbc.go"],
diff --git a/python/binary.go b/python/binary.go
index b106536..bc2768c 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -38,6 +38,7 @@
Main string
Srcs bazel.LabelListAttribute
Data bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
Python_version string
}
@@ -81,11 +82,13 @@
srcs := android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
data := android.BazelLabelForModuleSrc(ctx, m.properties.Data)
+ deps := android.BazelLabelForModuleDeps(ctx, m.properties.Libs)
attrs := &bazelPythonBinaryAttributes{
Main: main,
Srcs: bazel.MakeLabelListAttribute(srcs),
Data: bazel.MakeLabelListAttribute(data),
+ Deps: bazel.MakeLabelListAttribute(deps),
Python_version: python_version,
}
diff --git a/python/library.go b/python/library.go
index 9663b3c..a132216 100644
--- a/python/library.go
+++ b/python/library.go
@@ -17,11 +17,17 @@
// This file contains the module types for building Python library.
import (
+ "fmt"
+
"android/soong/android"
+ "android/soong/bazel"
+ "github.com/google/blueprint/proptools"
)
func init() {
registerPythonLibraryComponents(android.InitRegistrationContext)
+ android.RegisterBp2BuildMutator("python_library_host", PythonLibraryHostBp2Build)
+ android.RegisterBp2BuildMutator("python_library", PythonLibraryBp2Build)
}
func registerPythonLibraryComponents(ctx android.RegistrationContext) {
@@ -32,11 +38,79 @@
func PythonLibraryHostFactory() android.Module {
module := newModule(android.HostSupported, android.MultilibFirst)
+ android.InitBazelModule(module)
+
return module.init()
}
+type bazelPythonLibraryAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Data bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Srcs_version string
+}
+
+func PythonLibraryHostBp2Build(ctx android.TopDownMutatorContext) {
+ pythonLibBp2Build(ctx, "python_library_host")
+}
+
+func PythonLibraryBp2Build(ctx android.TopDownMutatorContext) {
+ pythonLibBp2Build(ctx, "python_library")
+}
+
+func pythonLibBp2Build(ctx android.TopDownMutatorContext, modType string) {
+ m, ok := ctx.Module().(*Module)
+ if !ok || !m.ConvertWithBp2build(ctx) {
+ return
+ }
+
+ // a Module can be something other than a `modType`
+ if ctx.ModuleType() != modType {
+ return
+ }
+
+ // TODO(b/182306917): this doesn't fully handle all nested props versioned
+ // by the python version, which would have been handled by the version split
+ // mutator. This is sufficient for very simple python_library modules under
+ // Bionic.
+ py3Enabled := proptools.BoolDefault(m.properties.Version.Py3.Enabled, true)
+ py2Enabled := proptools.BoolDefault(m.properties.Version.Py2.Enabled, false)
+ var python_version string
+ if py2Enabled && !py3Enabled {
+ python_version = "PY2"
+ } else if !py2Enabled && py3Enabled {
+ python_version = "PY3"
+ } else if !py2Enabled && !py3Enabled {
+ panic(fmt.Errorf(
+ "error for '%s' module: bp2build's %s converter doesn't understand having "+
+ "neither py2 nor py3 enabled", m.Name(), modType))
+ } else {
+ // do nothing, since python_version defaults to PY2ANDPY3
+ }
+
+ srcs := android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
+ data := android.BazelLabelForModuleSrc(ctx, m.properties.Data)
+ deps := android.BazelLabelForModuleDeps(ctx, m.properties.Libs)
+
+ attrs := &bazelPythonLibraryAttributes{
+ Srcs: bazel.MakeLabelListAttribute(srcs),
+ Data: bazel.MakeLabelListAttribute(data),
+ Deps: bazel.MakeLabelListAttribute(deps),
+ Srcs_version: python_version,
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ // Use the native py_library rule.
+ Rule_class: "py_library",
+ }
+
+ ctx.CreateBazelTargetModule(m.Name(), props, attrs)
+}
+
func PythonLibraryFactory() android.Module {
module := newModule(android.HostAndDeviceSupported, android.MultilibBoth)
+ android.InitBazelModule(module)
+
return module.init()
}
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 926d2ac..63a8f04 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -13,6 +13,7 @@
"external/minijail",
"external/rust",
"external/selinux/libselinux",
+ "external/uwb",
"external/vm_tools/p9",
"frameworks/native/libs/binder/rust",
"frameworks/proto_logging/stats",
@@ -25,6 +26,7 @@
"system/extras/simpleperf",
"system/hardware/interfaces/keystore2",
"system/librustutils",
+ "system/logging/liblog",
"system/logging/rust",
"system/security",
"system/tools/aidl",
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
index bdd54c5..f7b6681 100644
--- a/rust/project_json_test.go
+++ b/rust/project_json_test.go
@@ -36,7 +36,7 @@
// The JSON file is generated via WriteFileToOutputDir. Therefore, it
// won't appear in the Output of the TestingSingleton. Manually verify
// it exists.
- content, err := ioutil.ReadFile(filepath.Join(result.Config.BuildDir(), rustProjectJsonFileName))
+ content, err := ioutil.ReadFile(filepath.Join(result.Config.SoongOutDir(), rustProjectJsonFileName))
if err != nil {
t.Errorf("rust-project.json has not been generated")
}
diff --git a/scripts/construct_context.py b/scripts/construct_context.py
index f0658ba..3f601c3 100755
--- a/scripts/construct_context.py
+++ b/scripts/construct_context.py
@@ -25,57 +25,78 @@
def parse_args(args):
- """Parse commandline arguments."""
- parser = argparse.ArgumentParser()
- parser.add_argument('--target-sdk-version', default='', dest='sdk',
- help='specify target SDK version (as it appears in the manifest)')
- parser.add_argument('--host-context-for-sdk', dest='host_contexts',
- action='append', nargs=2, metavar=('sdk','context'),
- help='specify context on host for a given SDK version or "any" version')
- parser.add_argument('--target-context-for-sdk', dest='target_contexts',
- action='append', nargs=2, metavar=('sdk','context'),
- help='specify context on target for a given SDK version or "any" version')
- return parser.parse_args(args)
+ """Parse commandline arguments."""
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--target-sdk-version',
+ default='',
+ dest='sdk',
+ help='specify target SDK version (as it appears in the manifest)')
+ parser.add_argument(
+ '--host-context-for-sdk',
+ dest='host_contexts',
+ action='append',
+ nargs=2,
+ metavar=('sdk', 'context'),
+ help='specify context on host for a given SDK version or "any" version')
+ parser.add_argument(
+ '--target-context-for-sdk',
+ dest='target_contexts',
+ action='append',
+ nargs=2,
+ metavar=('sdk', 'context'),
+ help='specify context on target for a given SDK version or "any" '
+ 'version'
+ )
+ return parser.parse_args(args)
+
# Special keyword that means that the context should be added to class loader
# context regardless of the target SDK version.
any_sdk = 'any'
+
# We assume that the order of context arguments passed to this script is
# correct (matches the order computed by package manager). It is possible to
# sort them here, but Soong needs to use deterministic order anyway, so it can
# as well use the correct order.
def construct_context(versioned_contexts, target_sdk):
- context = []
- for [sdk, ctx] in versioned_contexts:
- if sdk == any_sdk or compare_version_gt(sdk, target_sdk):
- context.append(ctx)
- return context
+ context = []
+ for [sdk, ctx] in versioned_contexts:
+ if sdk == any_sdk or compare_version_gt(sdk, target_sdk):
+ context.append(ctx)
+ return context
+
def construct_contexts(args):
- host_context = construct_context(args.host_contexts, args.sdk)
- target_context = construct_context(args.target_contexts, args.sdk)
- context_sep = '#'
- return ('class_loader_context_arg=--class-loader-context=PCL[]{%s} ; ' % context_sep.join(host_context) +
- 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{%s}' % context_sep.join(target_context))
+ host_context = construct_context(args.host_contexts, args.sdk)
+ target_context = construct_context(args.target_contexts, args.sdk)
+ context_sep = '#'
+ return (
+ 'class_loader_context_arg=--class-loader-context=PCL[]{%s} ; ' %
+ context_sep.join(host_context) +
+ 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{%s}' #pylint: disable=line-too-long
+ % context_sep.join(target_context))
+
def main():
- """Program entry point."""
- try:
- args = parse_args(sys.argv[1:])
- if not args.sdk:
- raise SystemExit('target sdk version is not set')
- if not args.host_contexts:
- args.host_contexts = []
- if not args.target_contexts:
- args.target_contexts = []
+ """Program entry point."""
+ try:
+ args = parse_args(sys.argv[1:])
+ if not args.sdk:
+ raise SystemExit('target sdk version is not set')
+ if not args.host_contexts:
+ args.host_contexts = []
+ if not args.target_contexts:
+ args.target_contexts = []
- print(construct_contexts(args))
+ print(construct_contexts(args))
- # pylint: disable=broad-except
- except Exception as err:
- print('error: ' + str(err), file=sys.stderr)
- sys.exit(-1)
+ # pylint: disable=broad-except
+ except Exception as err:
+ print('error: ' + str(err), file=sys.stderr)
+ sys.exit(-1)
+
if __name__ == '__main__':
- main()
+ main()
diff --git a/scripts/construct_context_test.py b/scripts/construct_context_test.py
index 3b05f90..2ff5ac5 100755
--- a/scripts/construct_context_test.py
+++ b/scripts/construct_context_test.py
@@ -23,53 +23,63 @@
sys.dont_write_bytecode = True
+
def construct_contexts(arglist):
- args = cc.parse_args(arglist)
- return cc.construct_contexts(args)
+ args = cc.parse_args(arglist)
+ return cc.construct_contexts(args)
+
contexts = [
- '--host-context-for-sdk', '28', 'PCL[out/zdir/z.jar]',
- '--target-context-for-sdk', '28', 'PCL[/system/z.jar]',
- '--host-context-for-sdk', '29', 'PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]',
- '--target-context-for-sdk', '29', 'PCL[/system/x.jar]#PCL[/product/y.jar]',
- '--host-context-for-sdk', 'any', 'PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]',
- '--target-context-for-sdk', 'any', 'PCL[/system/a.jar]#PCL[/product/b.jar]',
+ '--host-context-for-sdk',
+ '28',
+ 'PCL[out/zdir/z.jar]',
+ '--target-context-for-sdk',
+ '28',
+ 'PCL[/system/z.jar]',
+ '--host-context-for-sdk',
+ '29',
+ 'PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]',
+ '--target-context-for-sdk',
+ '29',
+ 'PCL[/system/x.jar]#PCL[/product/y.jar]',
+ '--host-context-for-sdk',
+ 'any',
+ 'PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]',
+ '--target-context-for-sdk',
+ 'any',
+ 'PCL[/system/a.jar]#PCL[/product/b.jar]',
]
+#pylint: disable=line-too-long
class ConstructContextTest(unittest.TestCase):
- def test_construct_context_28(self):
- args = ['--target-sdk-version', '28'] + contexts
- result = construct_contexts(args)
- expect = ('class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/xdir/x.jar]'
- '#PCL[out/ydir/y.jar]'
- '#PCL[out/adir/a.jar]'
- '#PCL[out/bdir/b.jar]}'
- ' ; '
- 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/x.jar]'
- '#PCL[/product/y.jar]'
- '#PCL[/system/a.jar]'
- '#PCL[/product/b.jar]}')
- self.assertEqual(result, expect)
- def test_construct_context_29(self):
- args = ['--target-sdk-version', '29'] + contexts
- result = construct_contexts(args)
- expect = ('class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]'
- '#PCL[out/bdir/b.jar]}'
- ' ; '
- 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]'
- '#PCL[/product/b.jar]}')
- self.assertEqual(result, expect)
+ def test_construct_context_28(self):
+ args = ['--target-sdk-version', '28'] + contexts
+ result = construct_contexts(args)
+ expect = (
+ 'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/xdir/x.jar]#PCL[out/ydir/y.jar]#PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
+ ' ; '
+ 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/x.jar]#PCL[/product/y.jar]#PCL[/system/a.jar]#PCL[/product/b.jar]}')
+ self.assertEqual(result, expect)
- def test_construct_context_S(self):
- args = ['--target-sdk-version', 'S'] + contexts
- result = construct_contexts(args)
- expect = ('class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]'
- '#PCL[out/bdir/b.jar]}'
- ' ; '
- 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]'
- '#PCL[/product/b.jar]}')
- self.assertEqual(result, expect)
+ def test_construct_context_29(self):
+ args = ['--target-sdk-version', '29'] + contexts
+ result = construct_contexts(args)
+ expect = (
+ 'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
+ ' ; '
+ 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]#PCL[/product/b.jar]}')
+ self.assertEqual(result, expect)
+
+ def test_construct_context_S(self):
+ args = ['--target-sdk-version', 'S'] + contexts
+ result = construct_contexts(args)
+ expect = (
+ 'class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]#PCL[out/bdir/b.jar]}'
+ ' ; '
+ 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]#PCL[/product/b.jar]}')
+ self.assertEqual(result, expect)
+#pylint: enable=line-too-long
if __name__ == '__main__':
- unittest.main(verbosity=2)
+ unittest.main(verbosity=2)
diff --git a/scripts/conv_linker_config.py b/scripts/conv_linker_config.py
index 92f79da..e46efe4 100644
--- a/scripts/conv_linker_config.py
+++ b/scripts/conv_linker_config.py
@@ -20,178 +20,181 @@
import json
import os
-import linker_config_pb2
+import linker_config_pb2 #pylint: disable=import-error
from google.protobuf.descriptor import FieldDescriptor
from google.protobuf.json_format import ParseDict
from google.protobuf.text_format import MessageToString
def Proto(args):
- json_content = ''
- with open(args.source) as f:
- for line in f:
- if not line.lstrip().startswith('//'):
- json_content += line
- obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
- pb = ParseDict(obj, linker_config_pb2.LinkerConfig())
- with open(args.output, 'wb') as f:
- f.write(pb.SerializeToString())
+ json_content = ''
+ with open(args.source) as f:
+ for line in f:
+ if not line.lstrip().startswith('//'):
+ json_content += line
+ obj = json.loads(json_content, object_pairs_hook=collections.OrderedDict)
+ pb = ParseDict(obj, linker_config_pb2.LinkerConfig())
+ with open(args.output, 'wb') as f:
+ f.write(pb.SerializeToString())
def Print(args):
- with open(args.source, 'rb') as f:
- pb = linker_config_pb2.LinkerConfig()
- pb.ParseFromString(f.read())
- print(MessageToString(pb))
+ with open(args.source, 'rb') as f:
+ pb = linker_config_pb2.LinkerConfig()
+ pb.ParseFromString(f.read())
+ print(MessageToString(pb))
def SystemProvide(args):
- pb = linker_config_pb2.LinkerConfig()
- with open(args.source, 'rb') as f:
- pb.ParseFromString(f.read())
- libraries = args.value.split()
+ pb = linker_config_pb2.LinkerConfig()
+ with open(args.source, 'rb') as f:
+ pb.ParseFromString(f.read())
+ libraries = args.value.split()
- def IsInLibPath(lib_name):
- lib_path = os.path.join(args.system, 'lib', lib_name)
- lib64_path = os.path.join(args.system, 'lib64', lib_name)
- return os.path.exists(lib_path) or os.path.islink(lib_path) or os.path.exists(lib64_path) or os.path.islink(lib64_path)
+ def IsInLibPath(lib_name):
+ lib_path = os.path.join(args.system, 'lib', lib_name)
+ lib64_path = os.path.join(args.system, 'lib64', lib_name)
+ return os.path.exists(lib_path) or os.path.islink(
+ lib_path) or os.path.exists(lib64_path) or os.path.islink(
+ lib64_path)
- installed_libraries = list(filter(IsInLibPath, libraries))
- for item in installed_libraries:
- if item not in getattr(pb, 'provideLibs'):
- getattr(pb, 'provideLibs').append(item)
- with open(args.output, 'wb') as f:
- f.write(pb.SerializeToString())
+ installed_libraries = [lib for lib in libraries if IsInLibPath(lib)]
+ for item in installed_libraries:
+ if item not in getattr(pb, 'provideLibs'):
+ getattr(pb, 'provideLibs').append(item)
+ with open(args.output, 'wb') as f:
+ f.write(pb.SerializeToString())
def Append(args):
- pb = linker_config_pb2.LinkerConfig()
- with open(args.source, 'rb') as f:
- pb.ParseFromString(f.read())
+ pb = linker_config_pb2.LinkerConfig()
+ with open(args.source, 'rb') as f:
+ pb.ParseFromString(f.read())
- if getattr(type(pb), args.key).DESCRIPTOR.label == FieldDescriptor.LABEL_REPEATED:
- for value in args.value.split():
- getattr(pb, args.key).append(value)
- else:
- setattr(pb, args.key, args.value)
+ if getattr(type(pb),
+ args.key).DESCRIPTOR.label == FieldDescriptor.LABEL_REPEATED:
+ for value in args.value.split():
+ getattr(pb, args.key).append(value)
+ else:
+ setattr(pb, args.key, args.value)
- with open(args.output, 'wb') as f:
- f.write(pb.SerializeToString())
+ with open(args.output, 'wb') as f:
+ f.write(pb.SerializeToString())
+
def Merge(args):
- pb = linker_config_pb2.LinkerConfig()
- for other in args.input:
- with open(other, 'rb') as f:
- pb.MergeFromString(f.read())
+ pb = linker_config_pb2.LinkerConfig()
+ for other in args.input:
+ with open(other, 'rb') as f:
+ pb.MergeFromString(f.read())
- with open(args.out, 'wb') as f:
- f.write(pb.SerializeToString())
+ with open(args.out, 'wb') as f:
+ f.write(pb.SerializeToString())
+
def GetArgParser():
- parser = argparse.ArgumentParser()
- subparsers = parser.add_subparsers()
+ parser = argparse.ArgumentParser()
+ subparsers = parser.add_subparsers()
- parser_proto = subparsers.add_parser(
- 'proto', help='Convert the input JSON configuration file into protobuf.')
- parser_proto.add_argument(
- '-s',
- '--source',
- required=True,
- type=str,
- help='Source linker configuration file in JSON.')
- parser_proto.add_argument(
- '-o',
- '--output',
- required=True,
- type=str,
- help='Target path to create protobuf file.')
- parser_proto.set_defaults(func=Proto)
+ parser_proto = subparsers.add_parser(
+ 'proto',
+ help='Convert the input JSON configuration file into protobuf.')
+ parser_proto.add_argument(
+ '-s',
+ '--source',
+ required=True,
+ type=str,
+ help='Source linker configuration file in JSON.')
+ parser_proto.add_argument(
+ '-o',
+ '--output',
+ required=True,
+ type=str,
+ help='Target path to create protobuf file.')
+ parser_proto.set_defaults(func=Proto)
- print_proto = subparsers.add_parser(
- 'print', help='Print configuration in human-readable text format.')
- print_proto.add_argument(
- '-s',
- '--source',
- required=True,
- type=str,
- help='Source linker configuration file in protobuf.')
- print_proto.set_defaults(func=Print)
+ print_proto = subparsers.add_parser(
+ 'print', help='Print configuration in human-readable text format.')
+ print_proto.add_argument(
+ '-s',
+ '--source',
+ required=True,
+ type=str,
+ help='Source linker configuration file in protobuf.')
+ print_proto.set_defaults(func=Print)
- system_provide_libs = subparsers.add_parser(
- 'systemprovide', help='Append system provide libraries into the configuration.')
- system_provide_libs.add_argument(
- '-s',
- '--source',
- required=True,
- type=str,
- help='Source linker configuration file in protobuf.')
- system_provide_libs.add_argument(
- '-o',
- '--output',
- required=True,
- type=str,
- help='Target linker configuration file to write in protobuf.')
- system_provide_libs.add_argument(
- '--value',
- required=True,
- type=str,
- help='Values of the libraries to append. If there are more than one it should be separated by empty space')
- system_provide_libs.add_argument(
- '--system',
- required=True,
- type=str,
- help='Path of the system image.')
- system_provide_libs.set_defaults(func=SystemProvide)
+ system_provide_libs = subparsers.add_parser(
+ 'systemprovide',
+ help='Append system provide libraries into the configuration.')
+ system_provide_libs.add_argument(
+ '-s',
+ '--source',
+ required=True,
+ type=str,
+ help='Source linker configuration file in protobuf.')
+ system_provide_libs.add_argument(
+ '-o',
+ '--output',
+ required=True,
+ type=str,
+ help='Target linker configuration file to write in protobuf.')
+ system_provide_libs.add_argument(
+ '--value',
+ required=True,
+ type=str,
+ help='Values of the libraries to append. If there are more than one '
+ 'it should be separated by empty space'
+ )
+ system_provide_libs.add_argument(
+ '--system', required=True, type=str, help='Path of the system image.')
+ system_provide_libs.set_defaults(func=SystemProvide)
- append = subparsers.add_parser(
- 'append', help='Append value(s) to given key.')
- append.add_argument(
- '-s',
- '--source',
- required=True,
- type=str,
- help='Source linker configuration file in protobuf.')
- append.add_argument(
- '-o',
- '--output',
- required=True,
- type=str,
- help='Target linker configuration file to write in protobuf.')
- append.add_argument(
- '--key',
- required=True,
- type=str,
- help='.')
- append.add_argument(
- '--value',
- required=True,
- type=str,
- help='Values of the libraries to append. If there are more than one it should be separated by empty space')
- append.set_defaults(func=Append)
+ append = subparsers.add_parser(
+ 'append', help='Append value(s) to given key.')
+ append.add_argument(
+ '-s',
+ '--source',
+ required=True,
+ type=str,
+ help='Source linker configuration file in protobuf.')
+ append.add_argument(
+ '-o',
+ '--output',
+ required=True,
+ type=str,
+ help='Target linker configuration file to write in protobuf.')
+ append.add_argument('--key', required=True, type=str, help='.')
+ append.add_argument(
+ '--value',
+ required=True,
+ type=str,
+ help='Values of the libraries to append. If there are more than one'
+ 'it should be separated by empty space'
+ )
+ append.set_defaults(func=Append)
- append = subparsers.add_parser(
- 'merge', help='Merge configurations')
- append.add_argument(
- '-o',
- '--out',
- required=True,
- type=str,
- help='Ouptut linker configuration file to write in protobuf.')
- append.add_argument(
- '-i',
- '--input',
- nargs='+',
- type=str,
- help='Linker configuration files to merge.')
- append.set_defaults(func=Merge)
+ append = subparsers.add_parser('merge', help='Merge configurations')
+ append.add_argument(
+ '-o',
+ '--out',
+ required=True,
+ type=str,
+ help='Output linker configuration file to write in protobuf.')
+ append.add_argument(
+ '-i',
+ '--input',
+ nargs='+',
+ type=str,
+ help='Linker configuration files to merge.')
+ append.set_defaults(func=Merge)
- return parser
+ return parser
def main():
- args = GetArgParser().parse_args()
- args.func(args)
+ args = GetArgParser().parse_args()
+ args.func(args)
if __name__ == '__main__':
- main()
+ main()
diff --git a/scripts/get_clang_version.py b/scripts/get_clang_version.py
index f6efc5f..17bc88b 100755
--- a/scripts/get_clang_version.py
+++ b/scripts/get_clang_version.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
#
# Copyright (C) 2021 The Android Open Source Project
#
diff --git a/scripts/hiddenapi/generate_hiddenapi_lists.py b/scripts/hiddenapi/generate_hiddenapi_lists.py
index 5ab93d1..35e0948 100755
--- a/scripts/hiddenapi/generate_hiddenapi_lists.py
+++ b/scripts/hiddenapi/generate_hiddenapi_lists.py
@@ -16,8 +16,6 @@
"""Generate API lists for non-SDK API enforcement."""
import argparse
from collections import defaultdict, namedtuple
-import functools
-import os
import re
import sys
@@ -60,15 +58,15 @@
# For example, the max-target-P list is checked in as it was in P,
# but signatures have changes since then. The flag instructs this
# script to skip any entries which do not exist any more.
-FLAG_IGNORE_CONFLICTS = "ignore-conflicts"
+FLAG_IGNORE_CONFLICTS = 'ignore-conflicts'
# Option specified after one of FLAGS_API_LIST to express that all
# apis within a given set of packages should be assign the given flag.
-FLAG_PACKAGES = "packages"
+FLAG_PACKAGES = 'packages'
# Option specified after one of FLAGS_API_LIST to indicate an extra
# tag that should be added to the matching APIs.
-FLAG_TAG = "tag"
+FLAG_TAG = 'tag'
# Regex patterns of fields/methods used in serialization. These are
# considered public API despite being hidden.
@@ -84,24 +82,30 @@
# Single regex used to match serialization API. It combines all the
# SERIALIZATION_PATTERNS into a single regular expression.
-SERIALIZATION_REGEX = re.compile(r'.*->(' + '|'.join(SERIALIZATION_PATTERNS) + r')$')
+SERIALIZATION_REGEX = re.compile(r'.*->(' + '|'.join(SERIALIZATION_PATTERNS) +
+ r')$')
# Predicates to be used with filter_apis.
-HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags)
+HAS_NO_API_LIST_ASSIGNED = \
+ lambda api,flags: not FLAGS_API_LIST_SET.intersection(flags)
+
IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api)
class StoreOrderedOptions(argparse.Action):
- """An argparse action that stores a number of option arguments in the order that
- they were specified.
+ """An argparse action that stores a number of option arguments in the order
+
+ that they were specified.
"""
- def __call__(self, parser, args, values, option_string = None):
+
+ def __call__(self, parser, args, values, option_string=None):
items = getattr(args, self.dest, None)
if items is None:
items = []
items.append([option_string.lstrip('-'), values])
setattr(args, self.dest, items)
+
def get_args():
"""Parses command line arguments.
@@ -110,22 +114,43 @@
"""
parser = argparse.ArgumentParser()
parser.add_argument('--output', required=True)
- parser.add_argument('--csv', nargs='*', default=[], metavar='CSV_FILE',
+ parser.add_argument(
+ '--csv',
+ nargs='*',
+ default=[],
+ metavar='CSV_FILE',
help='CSV files to be merged into output')
for flag in ALL_FLAGS:
- parser.add_argument('--' + flag, dest='ordered_flags', metavar='TXT_FILE',
- action=StoreOrderedOptions, help='lists of entries with flag "' + flag + '"')
- parser.add_argument('--' + FLAG_IGNORE_CONFLICTS, dest='ordered_flags', nargs=0,
- action=StoreOrderedOptions, help='Indicates that only known and otherwise unassigned '
- 'entries should be assign the given flag. Must follow a list of entries and applies '
- 'to the preceding such list.')
- parser.add_argument('--' + FLAG_PACKAGES, dest='ordered_flags', nargs=0,
- action=StoreOrderedOptions, help='Indicates that the previous list of entries '
- 'is a list of packages. All members in those packages will be given the flag. '
- 'Must follow a list of entries and applies to the preceding such list.')
- parser.add_argument('--' + FLAG_TAG, dest='ordered_flags', nargs=1,
- action=StoreOrderedOptions, help='Adds an extra tag to the previous list of entries. '
+ parser.add_argument(
+ '--' + flag,
+ dest='ordered_flags',
+ metavar='TXT_FILE',
+ action=StoreOrderedOptions,
+ help='lists of entries with flag "' + flag + '"')
+ parser.add_argument(
+ '--' + FLAG_IGNORE_CONFLICTS,
+ dest='ordered_flags',
+ nargs=0,
+ action=StoreOrderedOptions,
+ help='Indicates that only known and otherwise unassigned '
+ 'entries should be assign the given flag. Must follow a list of '
+ 'entries and applies to the preceding such list.')
+ parser.add_argument(
+ '--' + FLAG_PACKAGES,
+ dest='ordered_flags',
+ nargs=0,
+ action=StoreOrderedOptions,
+ help='Indicates that the previous list of entries '
+ 'is a list of packages. All members in those packages will be given '
+ 'the flag. Must follow a list of entries and applies to the preceding '
+ 'such list.')
+ parser.add_argument(
+ '--' + FLAG_TAG,
+ dest='ordered_flags',
+ nargs=1,
+ action=StoreOrderedOptions,
+ help='Adds an extra tag to the previous list of entries. '
'Must follow a list of entries and applies to the preceding such list.')
return parser.parse_args()
@@ -143,9 +168,9 @@
Lines of the file as a list of string.
"""
with open(filename, 'r') as f:
- lines = f.readlines();
- lines = filter(lambda line: not line.startswith('#'), lines)
- lines = map(lambda line: line.strip(), lines)
+ lines = f.readlines()
+ lines = [line for line in lines if not line.startswith('#')]
+ lines = [line.strip() for line in lines]
return set(lines)
@@ -156,7 +181,7 @@
filename (string): Path to the file to be writing into.
lines (list): List of strings to write into the file.
"""
- lines = map(lambda line: line + '\n', lines)
+ lines = [line + '\n' for line in lines]
with open(filename, 'w') as f:
f.writelines(lines)
@@ -170,17 +195,19 @@
Returns:
The package name of the class containing the field/method.
"""
- full_class_name = signature.split(";->")[0]
+ full_class_name = signature.split(';->')[0]
# Example: Landroid/hardware/radio/V1_2/IRadio$Proxy
- if (full_class_name[0] != "L"):
- raise ValueError("Expected to start with 'L': %s" % full_class_name)
+ if full_class_name[0] != 'L':
+ raise ValueError("Expected to start with 'L': %s"
+ % full_class_name)
full_class_name = full_class_name[1:]
# If full_class_name doesn't contain '/', then package_name will be ''.
- package_name = full_class_name.rpartition("/")[0]
+ package_name = full_class_name.rpartition('/')[0]
return package_name.replace('/', '.')
class FlagsDict:
+
def __init__(self):
self._dict_keyset = set()
self._dict = defaultdict(set)
@@ -188,37 +215,43 @@
def _check_entries_set(self, keys_subset, source):
assert isinstance(keys_subset, set)
assert keys_subset.issubset(self._dict_keyset), (
- "Error: {} specifies signatures not present in code:\n"
- "{}"
- "Please visit go/hiddenapi for more information.").format(
- source, "".join(map(lambda x: " " + str(x) + "\n", keys_subset - self._dict_keyset)))
+ 'Error: {} specifies signatures not present in code:\n'
+ '{}'
+ 'Please visit go/hiddenapi for more information.').format(
+ source, ''.join(
+ [' ' + str(x) + '\n' for x in
+ keys_subset - self._dict_keyset]))
def _check_flags_set(self, flags_subset, source):
assert isinstance(flags_subset, set)
assert flags_subset.issubset(ALL_FLAGS_SET), (
- "Error processing: {}\n"
- "The following flags were not recognized: \n"
- "{}\n"
- "Please visit go/hiddenapi for more information.").format(
- source, "\n".join(flags_subset - ALL_FLAGS_SET))
+ 'Error processing: {}\n'
+ 'The following flags were not recognized: \n'
+ '{}\n'
+ 'Please visit go/hiddenapi for more information.').format(
+ source, '\n'.join(flags_subset - ALL_FLAGS_SET))
def filter_apis(self, filter_fn):
"""Returns APIs which match a given predicate.
- This is a helper function which allows to filter on both signatures (keys) and
- flags (values). The built-in filter() invokes the lambda only with dict's keys.
+ This is a helper function which allows to filter on both signatures
+ (keys) and
+ flags (values). The built-in filter() invokes the lambda only with
+ dict's keys.
Args:
- filter_fn : Function which takes two arguments (signature/flags) and returns a boolean.
+ filter_fn : Function which takes two arguments (signature/flags) and
+ returns a boolean.
Returns:
A set of APIs which match the predicate.
"""
- return set(filter(lambda x: filter_fn(x, self._dict[x]), self._dict_keyset))
+ return {x for x in self._dict_keyset if filter_fn(x, self._dict[x])}
def get_valid_subset_of_unassigned_apis(self, api_subset):
- """Sanitizes a key set input to only include keys which exist in the dictionary
- and have not been assigned any API list flags.
+ """Sanitizes a key set input to only include keys which exist in the
+
+ dictionary and have not been assigned any API list flags.
Args:
entries_subset (set/list): Key set to be sanitized.
@@ -227,7 +260,8 @@
Sanitized key set.
"""
assert isinstance(api_subset, set)
- return api_subset.intersection(self.filter_apis(HAS_NO_API_LIST_ASSIGNED))
+ return api_subset.intersection(
+ self.filter_apis(HAS_NO_API_LIST_ASSIGNED))
def generate_csv(self):
"""Constructs CSV entries from a dictionary.
@@ -235,15 +269,16 @@
Old versions of flags are used to generate the file.
Returns:
- List of lines comprising a CSV file. See "parse_and_merge_csv" for format description.
+ List of lines comprising a CSV file. See "parse_and_merge_csv" for
+ format description.
"""
lines = []
for api in self._dict:
- flags = sorted(self._dict[api])
- lines.append(",".join([api] + flags))
+ flags = sorted(self._dict[api])
+ lines.append(','.join([api] + flags))
return sorted(lines)
- def parse_and_merge_csv(self, csv_lines, source = "<unknown>"):
+ def parse_and_merge_csv(self, csv_lines, source='<unknown>'):
"""Parses CSV entries and merges them into a given dictionary.
The expected CSV format is:
@@ -251,21 +286,20 @@
Args:
csv_lines (list of strings): Lines read from a CSV file.
- source (string): Origin of `csv_lines`. Will be printed in error messages.
-
- Throws:
- AssertionError if parsed flags are invalid.
+ source (string): Origin of `csv_lines`. Will be printed in error
+ messages.
+ Throws: AssertionError if parsed flags are invalid.
"""
# Split CSV lines into arrays of values.
- csv_values = [ line.split(',') for line in csv_lines ]
+ csv_values = [line.split(',') for line in csv_lines]
# Update the full set of API signatures.
- self._dict_keyset.update([ csv[0] for csv in csv_values ])
+ self._dict_keyset.update([csv[0] for csv in csv_values])
# Check that all flags are known.
csv_flags = set()
for csv in csv_values:
- csv_flags.update(csv[1:])
+ csv_flags.update(csv[1:])
self._check_flags_set(csv_flags, source)
# Iterate over all CSV lines, find entry in dict and append flags to it.
@@ -275,47 +309,53 @@
flags.append(FLAG_SDK)
self._dict[csv[0]].update(flags)
- def assign_flag(self, flag, apis, source="<unknown>", tag = None):
+ def assign_flag(self, flag, apis, source='<unknown>', tag=None):
"""Assigns a flag to given subset of entries.
Args:
flag (string): One of ALL_FLAGS.
apis (set): Subset of APIs to receive the flag.
- source (string): Origin of `entries_subset`. Will be printed in error messages.
-
- Throws:
- AssertionError if parsed API signatures of flags are invalid.
+ source (string): Origin of `entries_subset`. Will be printed in
+ error messages.
+ Throws: AssertionError if parsed API signatures of flags are invalid.
"""
# Check that all APIs exist in the dict.
self._check_entries_set(apis, source)
# Check that the flag is known.
- self._check_flags_set(set([ flag ]), source)
+ self._check_flags_set(set([flag]), source)
- # Iterate over the API subset, find each entry in dict and assign the flag to it.
+ # Iterate over the API subset, find each entry in dict and assign the
+ # flag to it.
for api in apis:
self._dict[api].add(flag)
if tag:
self._dict[api].add(tag)
-FlagFile = namedtuple('FlagFile', ('flag', 'file', 'ignore_conflicts', 'packages', 'tag'))
+FlagFile = namedtuple('FlagFile',
+ ('flag', 'file', 'ignore_conflicts', 'packages', 'tag'))
+
def parse_ordered_flags(ordered_flags):
r = []
- currentflag, file, ignore_conflicts, packages, tag = None, None, False, False, None
+ currentflag, file, ignore_conflicts, packages, tag = None, None, False, \
+ False, None
for flag_value in ordered_flags:
flag, value = flag_value[0], flag_value[1]
if flag in ALL_FLAGS_SET:
if currentflag:
- r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag))
+ r.append(
+ FlagFile(currentflag, file, ignore_conflicts, packages,
+ tag))
ignore_conflicts, packages, tag = False, False, None
currentflag = flag
file = value
else:
if currentflag is None:
- raise argparse.ArgumentError('--%s is only allowed after one of %s' % (
- flag, ' '.join(['--%s' % f for f in ALL_FLAGS_SET])))
+ raise argparse.ArgumentError( #pylint: disable=no-value-for-parameter
+ '--%s is only allowed after one of %s' %
+ (flag, ' '.join(['--%s' % f for f in ALL_FLAGS_SET])))
if flag == FLAG_IGNORE_CONFLICTS:
ignore_conflicts = True
elif flag == FLAG_PACKAGES:
@@ -323,13 +363,12 @@
elif flag == FLAG_TAG:
tag = value[0]
-
if currentflag:
r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag))
return r
-def main(argv):
+def main(argv): #pylint: disable=unused-argument
# Parse arguments.
args = vars(get_args())
flagfiles = parse_ordered_flags(args['ordered_flags'] or [])
@@ -342,7 +381,7 @@
# contain the full set of APIs. Subsequent additions from text files
# will be able to detect invalid entries, and/or filter all as-yet
# unassigned entries.
- for filename in args["csv"]:
+ for filename in args['csv']:
flags.parse_and_merge_csv(read_lines(filename), filename)
# Combine inputs which do not require any particular order.
@@ -352,24 +391,28 @@
# (2) Merge text files with a known flag into the dictionary.
for info in flagfiles:
if (not info.ignore_conflicts) and (not info.packages):
- flags.assign_flag(info.flag, read_lines(info.file), info.file, info.tag)
+ flags.assign_flag(info.flag, read_lines(info.file), info.file,
+ info.tag)
# Merge text files where conflicts should be ignored.
# This will only assign the given flag if:
# (a) the entry exists, and
# (b) it has not been assigned any other flag.
- # Because of (b), this must run after all strict assignments have been performed.
+ # Because of (b), this must run after all strict assignments have been
+ # performed.
for info in flagfiles:
if info.ignore_conflicts:
- valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(info.file))
- flags.assign_flag(info.flag, valid_entries, filename, info.tag)
+ valid_entries = flags.get_valid_subset_of_unassigned_apis(
+ read_lines(info.file))
+ flags.assign_flag(info.flag, valid_entries, filename, info.tag) #pylint: disable=undefined-loop-variable
- # All members in the specified packages will be assigned the appropriate flag.
+ # All members in the specified packages will be assigned the appropriate
+ # flag.
for info in flagfiles:
if info.packages:
packages_needing_list = set(read_lines(info.file))
- should_add_signature_to_list = lambda sig,lists: extract_package(
- sig) in packages_needing_list and not lists
+ should_add_signature_to_list = lambda sig, lists: extract_package(
+ sig) in packages_needing_list and not lists #pylint: disable=cell-var-from-loop
valid_entries = flags.filter_apis(should_add_signature_to_list)
flags.assign_flag(info.flag, valid_entries, info.file, info.tag)
@@ -377,7 +420,8 @@
flags.assign_flag(FLAG_BLOCKED, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
# Write output.
- write_lines(args["output"], flags.generate_csv())
+ write_lines(args['output'], flags.generate_csv())
-if __name__ == "__main__":
+
+if __name__ == '__main__':
main(sys.argv)
diff --git a/scripts/hiddenapi/generate_hiddenapi_lists_test.py b/scripts/hiddenapi/generate_hiddenapi_lists_test.py
index b81424b..204de97 100755
--- a/scripts/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/scripts/hiddenapi/generate_hiddenapi_lists_test.py
@@ -15,34 +15,39 @@
# limitations under the License.
"""Unit tests for Hidden API list generation."""
import unittest
-from generate_hiddenapi_lists import *
+from generate_hiddenapi_lists import * # pylint: disable=wildcard-import,unused-wildcard-import
+
class TestHiddenapiListGeneration(unittest.TestCase):
-
def test_filter_apis(self):
# Initialize flags so that A and B are put on the allow list and
# C, D, E are left unassigned. Try filtering for the unassigned ones.
flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B,' + FLAG_SDK,
- 'C', 'D', 'E'])
+ flags.parse_and_merge_csv(
+ ['A,' + FLAG_SDK, 'B,' + FLAG_SDK, 'C', 'D', 'E']
+ )
filter_set = flags.filter_apis(lambda api, flags: not flags)
self.assertTrue(isinstance(filter_set, set))
- self.assertEqual(filter_set, set([ 'C', 'D', 'E' ]))
+ self.assertEqual(filter_set, set(['C', 'D', 'E']))
def test_get_valid_subset_of_unassigned_keys(self):
# Create flags where only A is unassigned.
flags = FlagsDict()
flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B', 'C'])
flags.assign_flag(FLAG_UNSUPPORTED, set(['C']))
- self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_SDK, 'B', 'C,' + FLAG_UNSUPPORTED ])
+ self.assertEqual(
+ flags.generate_csv(),
+ ['A,' + FLAG_SDK, 'B', 'C,' + FLAG_UNSUPPORTED],
+ )
# Check three things:
# (1) B is selected as valid unassigned
# (2) A is not selected because it is assigned to the allow list
# (3) D is not selected because it is not a valid key
self.assertEqual(
- flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])), set([ 'B' ]))
+ flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])),
+ set(['B']),
+ )
def test_parse_and_merge_csv(self):
flags = FlagsDict()
@@ -51,41 +56,48 @@
self.assertEqual(flags.generate_csv(), [])
# Test new additions.
- flags.parse_and_merge_csv([
- 'A,' + FLAG_UNSUPPORTED,
- 'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O,
- 'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
- 'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
- 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
- ])
- self.assertEqual(flags.generate_csv(), [
- 'A,' + FLAG_UNSUPPORTED,
- 'B,' + FLAG_BLOCKED + "," + FLAG_MAX_TARGET_O,
- 'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
- 'D,' + FLAG_TEST_API + ',' + FLAG_UNSUPPORTED,
- 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
- ])
+ flags.parse_and_merge_csv(
+ [
+ 'A,' + FLAG_UNSUPPORTED,
+ 'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O,
+ 'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
+ 'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
+ 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
+ ]
+ )
+ self.assertEqual(
+ flags.generate_csv(),
+ [
+ 'A,' + FLAG_UNSUPPORTED,
+ 'B,' + FLAG_BLOCKED + "," + FLAG_MAX_TARGET_O,
+ 'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
+ 'D,' + FLAG_TEST_API + ',' + FLAG_UNSUPPORTED,
+ 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
+ ],
+ )
# Test unknown flag.
with self.assertRaises(AssertionError):
- flags.parse_and_merge_csv([ 'Z,foo' ])
+ flags.parse_and_merge_csv(['Z,foo'])
def test_assign_flag(self):
flags = FlagsDict()
flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B'])
# Test new additions.
- flags.assign_flag(FLAG_UNSUPPORTED, set([ 'A', 'B' ]))
- self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_SDK + "," + FLAG_UNSUPPORTED, 'B,' + FLAG_UNSUPPORTED ])
+ flags.assign_flag(FLAG_UNSUPPORTED, set(['A', 'B']))
+ self.assertEqual(
+ flags.generate_csv(),
+ ['A,' + FLAG_SDK + "," + FLAG_UNSUPPORTED, 'B,' + FLAG_UNSUPPORTED],
+ )
# Test invalid API signature.
with self.assertRaises(AssertionError):
- flags.assign_flag(FLAG_SDK, set([ 'C' ]))
+ flags.assign_flag(FLAG_SDK, set(['C']))
# Test invalid flag.
with self.assertRaises(AssertionError):
- flags.assign_flag('foo', set([ 'A' ]))
+ flags.assign_flag('foo', set(['A']))
def test_extract_package(self):
signature = 'Lcom/foo/bar/Baz;->method1()Lcom/bar/Baz;'
@@ -100,5 +112,6 @@
expected_package = 'com.foo_bar.baz'
self.assertEqual(extract_package(signature), expected_package)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/scripts/hiddenapi/merge_csv.py b/scripts/hiddenapi/merge_csv.py
index a65326c..c17ec25 100755
--- a/scripts/hiddenapi/merge_csv.py
+++ b/scripts/hiddenapi/merge_csv.py
@@ -13,8 +13,7 @@
# 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.
-"""
-Merge multiple CSV files, possibly with different columns.
+"""Merge multiple CSV files, possibly with different columns.
"""
import argparse
@@ -26,34 +25,52 @@
from zipfile import ZipFile
-args_parser = argparse.ArgumentParser(description='Merge given CSV files into a single one.')
-args_parser.add_argument('--header', help='Comma separated field names; '
- 'if missing determines the header from input files.')
-args_parser.add_argument('--zip_input', help='Treat files as ZIP archives containing CSV files to merge.',
- action="store_true")
-args_parser.add_argument('--key_field', help='The name of the field by which the rows should be sorted. '
- 'Must be in the field names. '
- 'Will be the first field in the output. '
- 'All input files must be sorted by that field.')
-args_parser.add_argument('--output', help='Output file for merged CSV.',
- default='-', type=argparse.FileType('w'))
+args_parser = argparse.ArgumentParser(
+ description='Merge given CSV files into a single one.'
+)
+args_parser.add_argument(
+ '--header',
+ help='Comma separated field names; '
+ 'if missing determines the header from input files.',
+)
+args_parser.add_argument(
+ '--zip_input',
+ help='Treat files as ZIP archives containing CSV files to merge.',
+ action="store_true",
+)
+args_parser.add_argument(
+ '--key_field',
+ help='The name of the field by which the rows should be sorted. '
+ 'Must be in the field names. '
+ 'Will be the first field in the output. '
+ 'All input files must be sorted by that field.',
+)
+args_parser.add_argument(
+ '--output',
+ help='Output file for merged CSV.',
+ default='-',
+ type=argparse.FileType('w'),
+)
args_parser.add_argument('files', nargs=argparse.REMAINDER)
args = args_parser.parse_args()
-def dict_reader(input):
- return csv.DictReader(input, delimiter=',', quotechar='|')
+def dict_reader(csvfile):
+ return csv.DictReader(csvfile, delimiter=',', quotechar='|')
+
csv_readers = []
-if not(args.zip_input):
+if not args.zip_input:
for file in args.files:
csv_readers.append(dict_reader(open(file, 'r')))
else:
for file in args.files:
- with ZipFile(file) as zip:
- for entry in zip.namelist():
+ with ZipFile(file) as zipfile:
+ for entry in zipfile.namelist():
if entry.endswith('.uau'):
- csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
+ csv_readers.append(
+ dict_reader(io.TextIOWrapper(zipfile.open(entry, 'r')))
+ )
if args.header:
fieldnames = args.header.split(',')
@@ -73,8 +90,8 @@
keyField = args.key_field
if keyField:
assert keyField in fieldnames, (
- "--key_field {} not found, must be one of {}\n").format(
- keyField, ",".join(fieldnames))
+ "--key_field {} not found, must be one of {}\n"
+ ).format(keyField, ",".join(fieldnames))
# Make the key field the first field in the output
keyFieldIndex = fieldnames.index(args.key_field)
fieldnames.insert(0, fieldnames.pop(keyFieldIndex))
@@ -83,11 +100,17 @@
all_rows = heapq.merge(*csv_readers, key=operator.itemgetter(keyField))
# Write all rows from the input files to the output:
-writer = csv.DictWriter(args.output, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
- dialect='unix', fieldnames=fieldnames)
+writer = csv.DictWriter(
+ args.output,
+ delimiter=',',
+ quotechar='|',
+ quoting=csv.QUOTE_MINIMAL,
+ dialect='unix',
+ fieldnames=fieldnames,
+)
writer.writeheader()
# Read all the rows from the input and write them to the output in the correct
# order:
for row in all_rows:
- writer.writerow(row)
+ writer.writerow(row)
diff --git a/scripts/hiddenapi/signature_patterns.py b/scripts/hiddenapi/signature_patterns.py
index a7c5bb4..0acb2a0 100755
--- a/scripts/hiddenapi/signature_patterns.py
+++ b/scripts/hiddenapi/signature_patterns.py
@@ -13,22 +13,26 @@
# 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.
-"""
-Generate a set of signature patterns from the modular flags generated by a
+"""Generate a set of signature patterns from the modular flags generated by a
bootclasspath_fragment that can be used to select a subset of monolithic flags
against which the modular flags can be compared.
"""
import argparse
import csv
+import sys
-def dict_reader(input):
- return csv.DictReader(input, delimiter=',', quotechar='|', fieldnames=['signature'])
+def dict_reader(csvfile):
+ return csv.DictReader(
+ csvfile, delimiter=',', quotechar='|', fieldnames=['signature']
+ )
+
def produce_patterns_from_file(file):
with open(file, 'r') as f:
return produce_patterns_from_stream(f)
+
def produce_patterns_from_stream(stream):
# Read in all the signatures into a list and remove member names.
patterns = set()
@@ -38,18 +42,26 @@
# Remove the class specific member signature
pieces = text.split(";->")
qualifiedClassName = pieces[0]
- # Remove inner class names as they cannot be separated from the containing outer class.
+ # Remove inner class names as they cannot be separated
+ # from the containing outer class.
pieces = qualifiedClassName.split("$", maxsplit=1)
pattern = pieces[0]
patterns.add(pattern)
- patterns = list(patterns)
+ patterns = list(patterns) #pylint: disable=redefined-variable-type
patterns.sort()
return patterns
+
def main(args):
- args_parser = argparse.ArgumentParser(description='Generate a set of signature patterns that select a subset of monolithic hidden API files.')
- args_parser.add_argument('--flags', help='The stub flags file which contains an entry for every dex member')
+ args_parser = argparse.ArgumentParser(
+ description='Generate a set of signature patterns '
+ 'that select a subset of monolithic hidden API files.'
+ )
+ args_parser.add_argument(
+ '--flags',
+ help='The stub flags file which contains an entry for every dex member',
+ )
args_parser.add_argument('--output', help='Generated signature prefixes')
args = args_parser.parse_args(args)
@@ -62,5 +74,6 @@
outputFile.write(pattern)
outputFile.write("\n")
+
if __name__ == "__main__":
main(sys.argv[1:])
diff --git a/scripts/hiddenapi/signature_patterns_test.py b/scripts/hiddenapi/signature_patterns_test.py
index 0431f45..3babe54 100755
--- a/scripts/hiddenapi/signature_patterns_test.py
+++ b/scripts/hiddenapi/signature_patterns_test.py
@@ -18,21 +18,25 @@
import io
import unittest
-from signature_patterns import *
+from signature_patterns import * #pylint: disable=unused-wildcard-import,wildcard-import
+
class TestGeneratedPatterns(unittest.TestCase):
-
- def produce_patterns_from_string(self, csv):
- with io.StringIO(csv) as f:
+ def produce_patterns_from_string(self, csvdata):
+ with io.StringIO(csvdata) as f:
return produce_patterns_from_stream(f)
def test_generate(self):
- patterns = self.produce_patterns_from_string('''
+ #pylint: disable=line-too-long
+ patterns = self.produce_patterns_from_string(
+ '''
Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V,blocked
Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;,public-api
Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
-''')
+'''
+ )
+ #pylint: enable=line-too-long
expected = [
"java/lang/Character",
"java/lang/Object",
@@ -40,5 +44,6 @@
]
self.assertEqual(expected, patterns)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/scripts/hiddenapi/verify_overlaps.py b/scripts/hiddenapi/verify_overlaps.py
index 6432bf1..4cd7e63 100755
--- a/scripts/hiddenapi/verify_overlaps.py
+++ b/scripts/hiddenapi/verify_overlaps.py
@@ -13,8 +13,7 @@
# 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.
-"""
-Verify that one set of hidden API flags is a subset of another.
+"""Verify that one set of hidden API flags is a subset of another.
"""
import argparse
@@ -22,9 +21,9 @@
import sys
from itertools import chain
+#pylint: disable=line-too-long
class InteriorNode:
- """
- An interior node in a trie.
+ """An interior node in a trie.
Each interior node has a dict that maps from an element of a signature to
either another interior node or a leaf. Each interior node represents either
@@ -52,19 +51,21 @@
Attributes:
nodes: a dict from an element of the signature to the Node/Leaf
- containing the next element/value.
+ containing the next element/value.
"""
+ #pylint: enable=line-too-long
+
def __init__(self):
self.nodes = {}
+ #pylint: disable=line-too-long
def signatureToElements(self, signature):
- """
- Split a signature or a prefix into a number of elements:
+ """Split a signature or a prefix into a number of elements:
1. The packages (excluding the leading L preceding the first package).
2. The class names, from outermost to innermost.
3. The member signature.
-
- e.g. Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
+ e.g.
+ Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
will be broken down into these elements:
1. package:java
2. package:lang
@@ -88,19 +89,21 @@
elements = parts[0].split("/")
packages = elements[0:-1]
className = elements[-1]
- if className == "*" or className == "**":
+ if className in ("*" , "**"): #pylint: disable=no-else-return
# Cannot specify a wildcard and target a specific member
if len(member) != 0:
- raise Exception("Invalid signature %s: contains wildcard %s and member signature %s"
- % (signature, className, member[0]))
+ raise Exception(
+ "Invalid signature %s: contains wildcard %s and member " \
+ "signature %s"
+ % (signature, className, member[0]))
wildcard = [className]
# Assemble the parts into a single list, adding prefixes to identify
# the different parts.
# 0 - package:java
# 1 - package:lang
# 2 - *
- return list(chain(map(lambda x : "package:" + x, packages),
- wildcard))
+ return list(
+ chain(["package:" + x for x in packages], wildcard))
else:
# Split the class name into outer / inner classes
# 0 - Character
@@ -113,13 +116,16 @@
# 2 - class:Character
# 3 - class:UnicodeScript
# 4 - member:of(I)Ljava/lang/Character$UnicodeScript;
- return list(chain(map(lambda x : "package:" + x, packages),
- map(lambda x : "class:" + x, classes),
- map(lambda x : "member:" + x, member)))
+ return list(
+ chain(
+ ["package:" + x for x in packages],
+ ["class:" + x for x in classes],
+ ["member:" + x for x in member]))
+ #pylint: enable=line-too-long
def add(self, signature, value):
- """
- Associate the value with the specific signature.
+ """Associate the value with the specific signature.
+
:param signature: the member signature
:param value: the value to associated with the signature
:return: n/a
@@ -132,21 +138,22 @@
if element in node.nodes:
node = node.nodes[element]
else:
- next = InteriorNode()
- node.nodes[element] = next
- node = next
+ next_node = InteriorNode()
+ node.nodes[element] = next_node
+ node = next_node
# Add a Leaf containing the value and associate it with the member
# signature within the class.
lastElement = elements[-1]
if not lastElement.startswith("member:"):
- raise Exception("Invalid signature: %s, does not identify a specific member" % signature)
+ raise Exception(
+ "Invalid signature: %s, does not identify a specific member" %
+ signature)
if lastElement in node.nodes:
raise Exception("Duplicate signature: %s" % signature)
node.nodes[lastElement] = Leaf(value)
def getMatchingRows(self, pattern):
- """
- Get the values (plural) associated with the pattern.
+ """Get the values (plural) associated with the pattern.
e.g. If the pattern is a full signature then this will return a list
containing the value associated with that signature.
@@ -175,13 +182,13 @@
elements = self.signatureToElements(pattern)
node = self
# Include all values from this node and all its children.
- selector = lambda x : True
+ selector = lambda x: True
lastElement = elements[-1]
- if lastElement == "*" or lastElement == "**":
+ if lastElement in ("*", "**"):
elements = elements[:-1]
if lastElement == "*":
# Do not include values from sub-packages.
- selector = lambda x : not x.startswith("package:")
+ selector = lambda x: not x.startswith("package:")
for element in elements:
if element in node.nodes:
node = node.nodes[element]
@@ -190,19 +197,18 @@
return chain.from_iterable(node.values(selector))
def values(self, selector):
- """
- :param selector: a function that can be applied to a key in the nodes
+ """:param selector: a function that can be applied to a key in the nodes
attribute to determine whether to return its values.
- :return: A list of iterables of all the values associated with this
- node and its children.
+
+ :return: A list of iterables of all the values associated with
+ this node and its children.
"""
values = []
self.appendValues(values, selector)
return values
def appendValues(self, values, selector):
- """
- Append the values associated with this node and its children to the
+ """Append the values associated with this node and its children to the
list.
For each item (key, child) in nodes the child node's values are returned
@@ -216,105 +222,116 @@
"""
for key, node in self.nodes.items():
if selector(key):
- node.appendValues(values, lambda x : True)
+ node.appendValues(values, lambda x: True)
+
class Leaf:
- """
- A leaf of the trie
+ """A leaf of the trie
Attributes:
value: the value associated with this leaf.
"""
+
def __init__(self, value):
self.value = value
- def values(self, selector):
- """
- :return: A list of a list of the value associated with this node.
+ def values(self, selector): #pylint: disable=unused-argument
+ """:return: A list of a list of the value associated with this node.
"""
return [[self.value]]
- def appendValues(self, values, selector):
- """
- Appends a list of the value associated with this node to the list.
+ def appendValues(self, values, selector): #pylint: disable=unused-argument
+ """Appends a list of the value associated with this node to the list.
+
:param values: a list of a iterables of values.
"""
values.append([self.value])
-def dict_reader(input):
- return csv.DictReader(input, delimiter=',', quotechar='|', fieldnames=['signature'])
+
+def dict_reader(csvfile):
+ return csv.DictReader(
+ csvfile, delimiter=",", quotechar="|", fieldnames=["signature"])
+
def read_flag_trie_from_file(file):
- with open(file, 'r') as stream:
+ with open(file, "r") as stream:
return read_flag_trie_from_stream(stream)
+
def read_flag_trie_from_stream(stream):
trie = InteriorNode()
reader = dict_reader(stream)
for row in reader:
- signature = row['signature']
+ signature = row["signature"]
trie.add(signature, row)
return trie
-def extract_subset_from_monolithic_flags_as_dict_from_file(monolithicTrie, patternsFile):
- """
- Extract a subset of flags from the dict containing all the monolithic flags.
+
+def extract_subset_from_monolithic_flags_as_dict_from_file(
+ monolithicTrie, patternsFile):
+ """Extract a subset of flags from the dict containing all the monolithic
+ flags.
:param monolithicFlagsDict: the dict containing all the monolithic flags.
:param patternsFile: a file containing a list of signature patterns that
define the subset.
:return: the dict from signature to row.
"""
- with open(patternsFile, 'r') as stream:
- return extract_subset_from_monolithic_flags_as_dict_from_stream(monolithicTrie, stream)
+ with open(patternsFile, "r") as stream:
+ return extract_subset_from_monolithic_flags_as_dict_from_stream(
+ monolithicTrie, stream)
-def extract_subset_from_monolithic_flags_as_dict_from_stream(monolithicTrie, stream):
- """
- Extract a subset of flags from the trie containing all the monolithic flags.
+
+def extract_subset_from_monolithic_flags_as_dict_from_stream(
+ monolithicTrie, stream):
+ """Extract a subset of flags from the trie containing all the monolithic
+ flags.
:param monolithicTrie: the trie containing all the monolithic flags.
:param stream: a stream containing a list of signature patterns that define
the subset.
:return: the dict from signature to row.
"""
- dict = {}
+ dict_signature_to_row = {}
for pattern in stream:
pattern = pattern.rstrip()
rows = monolithicTrie.getMatchingRows(pattern)
for row in rows:
- signature = row['signature']
- dict[signature] = row
- return dict
+ signature = row["signature"]
+ dict_signature_to_row[signature] = row
+ return dict_signature_to_row
+
def read_signature_csv_from_stream_as_dict(stream):
- """
- Read the csv contents from the stream into a dict. The first column is assumed to be the
- signature and used as the key. The whole row is stored as the value.
+ """Read the csv contents from the stream into a dict. The first column is
+ assumed to be the signature and used as the key.
+ The whole row is stored as the value.
:param stream: the csv contents to read
:return: the dict from signature to row.
"""
- dict = {}
+ dict_signature_to_row = {}
reader = dict_reader(stream)
for row in reader:
- signature = row['signature']
- dict[signature] = row
- return dict
+ signature = row["signature"]
+ dict_signature_to_row[signature] = row
+ return dict_signature_to_row
+
def read_signature_csv_from_file_as_dict(csvFile):
- """
- Read the csvFile into a dict. The first column is assumed to be the
- signature and used as the key. The whole row is stored as the value.
+ """Read the csvFile into a dict. The first column is assumed to be the
+ signature and used as the key.
+ The whole row is stored as the value.
:param csvFile: the csv file to read
:return: the dict from signature to row.
"""
- with open(csvFile, 'r') as f:
+ with open(csvFile, "r") as f:
return read_signature_csv_from_stream_as_dict(f)
+
def compare_signature_flags(monolithicFlagsDict, modularFlagsDict):
- """
- Compare the signature flags between the two dicts.
+ """Compare the signature flags between the two dicts.
:param monolithicFlagsDict: the dict containing the subset of the monolithic
flags that should be equal to the modular flags.
@@ -327,7 +344,8 @@
mismatchingSignatures = []
# Create a sorted set of all the signatures from both the monolithic and
# modular dicts.
- allSignatures = sorted(set(chain(monolithicFlagsDict.keys(), modularFlagsDict.keys())))
+ allSignatures = sorted(
+ set(chain(monolithicFlagsDict.keys(), modularFlagsDict.keys())))
for signature in allSignatures:
monolithicRow = monolithicFlagsDict.get(signature, {})
monolithicFlags = monolithicRow.get(None, [])
@@ -337,13 +355,21 @@
else:
modularFlags = ["blocked"]
if monolithicFlags != modularFlags:
- mismatchingSignatures.append((signature, modularFlags, monolithicFlags))
+ mismatchingSignatures.append(
+ (signature, modularFlags, monolithicFlags))
return mismatchingSignatures
+
def main(argv):
- args_parser = argparse.ArgumentParser(description='Verify that sets of hidden API flags are each a subset of the monolithic flag file.')
- args_parser.add_argument('monolithicFlags', help='The monolithic flag file')
- args_parser.add_argument('modularFlags', nargs=argparse.REMAINDER, help='Flags produced by individual bootclasspath_fragment modules')
+ args_parser = argparse.ArgumentParser(
+ description="Verify that sets of hidden API flags are each a subset of "
+ "the monolithic flag file."
+ )
+ args_parser.add_argument("monolithicFlags", help="The monolithic flag file")
+ args_parser.add_argument(
+ "modularFlags",
+ nargs=argparse.REMAINDER,
+ help="Flags produced by individual bootclasspath_fragment modules")
args = args_parser.parse_args(argv[1:])
# Read in all the flags into the trie
@@ -358,9 +384,13 @@
parts = modularPair.split(":")
modularFlagsPath = parts[0]
modularPatternsPath = parts[1]
- modularFlagsDict = read_signature_csv_from_file_as_dict(modularFlagsPath)
- monolithicFlagsSubsetDict = extract_subset_from_monolithic_flags_as_dict_from_file(monolithicTrie, modularPatternsPath)
- mismatchingSignatures = compare_signature_flags(monolithicFlagsSubsetDict, modularFlagsDict)
+ modularFlagsDict = read_signature_csv_from_file_as_dict(
+ modularFlagsPath)
+ monolithicFlagsSubsetDict = \
+ extract_subset_from_monolithic_flags_as_dict_from_file(
+ monolithicTrie, modularPatternsPath)
+ mismatchingSignatures = compare_signature_flags(
+ monolithicFlagsSubsetDict, modularFlagsDict)
if mismatchingSignatures:
failed = True
print("ERROR: Hidden API flags are inconsistent:")
@@ -369,11 +399,12 @@
for mismatch in mismatchingSignatures:
signature = mismatch[0]
print()
- print("< " + ",".join([signature]+ mismatch[1]))
- print("> " + ",".join([signature]+ mismatch[2]))
+ print("< " + ",".join([signature] + mismatch[1]))
+ print("> " + ",".join([signature] + mismatch[2]))
if failed:
sys.exit(1)
+
if __name__ == "__main__":
main(sys.argv)
diff --git a/scripts/hiddenapi/verify_overlaps_test.py b/scripts/hiddenapi/verify_overlaps_test.py
index 00c0611..22a1cdf 100755
--- a/scripts/hiddenapi/verify_overlaps_test.py
+++ b/scripts/hiddenapi/verify_overlaps_test.py
@@ -13,12 +13,12 @@
# 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.
-
"""Unit tests for verify_overlaps_test.py."""
import io
import unittest
-from verify_overlaps import *
+from verify_overlaps import * #pylint: disable=unused-wildcard-import,wildcard-import
+
class TestSignatureToElements(unittest.TestCase):
@@ -34,8 +34,10 @@
'class:1',
'member:<init>()V',
]
- self.assertEqual(expected, self.signatureToElements(
- "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V"))
+ self.assertEqual(
+ expected,
+ self.signatureToElements(
+ 'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V'))
def test_signatureToElements_2(self):
expected = [
@@ -44,8 +46,9 @@
'class:Object',
'member:hashCode()I',
]
- self.assertEqual(expected, self.signatureToElements(
- "Ljava/lang/Object;->hashCode()I"))
+ self.assertEqual(
+ expected,
+ self.signatureToElements('Ljava/lang/Object;->hashCode()I'))
def test_signatureToElements_3(self):
expected = [
@@ -56,39 +59,46 @@
'class:ExternalSyntheticLambda0',
'member:<init>(Ljava/lang/CharSequence;)V',
]
- self.assertEqual(expected, self.signatureToElements(
- "Ljava/lang/CharSequence$$ExternalSyntheticLambda0;"
- "-><init>(Ljava/lang/CharSequence;)V"))
+ self.assertEqual(
+ expected,
+ self.signatureToElements(
+ 'Ljava/lang/CharSequence$$ExternalSyntheticLambda0;'
+ '-><init>(Ljava/lang/CharSequence;)V'))
+#pylint: disable=line-too-long
class TestDetectOverlaps(unittest.TestCase):
- def read_flag_trie_from_string(self, csv):
- with io.StringIO(csv) as f:
+ def read_flag_trie_from_string(self, csvdata):
+ with io.StringIO(csvdata) as f:
return read_flag_trie_from_stream(f)
- def read_signature_csv_from_string_as_dict(self, csv):
- with io.StringIO(csv) as f:
+ def read_signature_csv_from_string_as_dict(self, csvdata):
+ with io.StringIO(csvdata) as f:
return read_signature_csv_from_stream_as_dict(f)
- def extract_subset_from_monolithic_flags_as_dict_from_string(self, monolithic, patterns):
+ def extract_subset_from_monolithic_flags_as_dict_from_string(
+ self, monolithic, patterns):
with io.StringIO(patterns) as f:
- return extract_subset_from_monolithic_flags_as_dict_from_stream(monolithic, f)
+ return extract_subset_from_monolithic_flags_as_dict_from_stream(
+ monolithic, f)
- extractInput = '''
+ extractInput = """
Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
Ljava/util/zip/ZipFile;-><clinit>()V,blocked
Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;,blocked
Ljava/lang/Character;->serialVersionUID:J,sdk
Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V,blocked
-'''
+"""
def test_extract_subset_signature(self):
- monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+ monolithic = self.read_flag_trie_from_string(
+ TestDetectOverlaps.extractInput)
patterns = 'Ljava/lang/Object;->hashCode()I'
- subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(
+ monolithic, patterns)
expected = {
'Ljava/lang/Object;->hashCode()I': {
None: ['public-api', 'system-api', 'test-api'],
@@ -98,11 +108,13 @@
self.assertEqual(expected, subset)
def test_extract_subset_class(self):
- monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+ monolithic = self.read_flag_trie_from_string(
+ TestDetectOverlaps.extractInput)
patterns = 'java/lang/Object'
- subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(
+ monolithic, patterns)
expected = {
'Ljava/lang/Object;->hashCode()I': {
None: ['public-api', 'system-api', 'test-api'],
@@ -116,16 +128,20 @@
self.assertEqual(expected, subset)
def test_extract_subset_outer_class(self):
- monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+ monolithic = self.read_flag_trie_from_string(
+ TestDetectOverlaps.extractInput)
patterns = 'java/lang/Character'
- subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(
+ monolithic, patterns)
expected = {
- 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
- None: ['blocked'],
- 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
- },
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;':
+ {
+ None: ['blocked'],
+ 'signature':
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
+ },
'Ljava/lang/Character;->serialVersionUID:J': {
None: ['sdk'],
'signature': 'Ljava/lang/Character;->serialVersionUID:J',
@@ -134,30 +150,38 @@
self.assertEqual(expected, subset)
def test_extract_subset_nested_class(self):
- monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+ monolithic = self.read_flag_trie_from_string(
+ TestDetectOverlaps.extractInput)
patterns = 'java/lang/Character$UnicodeScript'
- subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(
+ monolithic, patterns)
expected = {
- 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
- None: ['blocked'],
- 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
- },
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;':
+ {
+ None: ['blocked'],
+ 'signature':
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
+ },
}
self.assertEqual(expected, subset)
def test_extract_subset_package(self):
- monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+ monolithic = self.read_flag_trie_from_string(
+ TestDetectOverlaps.extractInput)
patterns = 'java/lang/*'
- subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(
+ monolithic, patterns)
expected = {
- 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
- None: ['blocked'],
- 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
- },
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;':
+ {
+ None: ['blocked'],
+ 'signature':
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
+ },
'Ljava/lang/Character;->serialVersionUID:J': {
None: ['sdk'],
'signature': 'Ljava/lang/Character;->serialVersionUID:J',
@@ -178,16 +202,20 @@
self.assertEqual(expected, subset)
def test_extract_subset_recursive_package(self):
- monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+ monolithic = self.read_flag_trie_from_string(
+ TestDetectOverlaps.extractInput)
patterns = 'java/**'
- subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
+ subset = self.extract_subset_from_monolithic_flags_as_dict_from_string(
+ monolithic, patterns)
expected = {
- 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;': {
- None: ['blocked'],
- 'signature': 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
- },
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;':
+ {
+ None: ['blocked'],
+ 'signature':
+ 'Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;',
+ },
'Ljava/lang/Character;->serialVersionUID:J': {
None: ['sdk'],
'signature': 'Ljava/lang/Character;->serialVersionUID:J',
@@ -212,47 +240,53 @@
self.assertEqual(expected, subset)
def test_extract_subset_invalid_pattern_wildcard_and_member(self):
- monolithic = self.read_flag_trie_from_string(TestDetectOverlaps.extractInput)
+ monolithic = self.read_flag_trie_from_string(
+ TestDetectOverlaps.extractInput)
patterns = 'Ljava/lang/*;->hashCode()I'
with self.assertRaises(Exception) as context:
- self.extract_subset_from_monolithic_flags_as_dict_from_string(monolithic, patterns)
- self.assertTrue("contains wildcard * and member signature hashCode()I" in str(context.exception))
+ self.extract_subset_from_monolithic_flags_as_dict_from_string(
+ monolithic, patterns)
+ self.assertTrue('contains wildcard * and member signature hashCode()I'
+ in str(context.exception))
def test_read_trie_duplicate(self):
with self.assertRaises(Exception) as context:
- self.read_flag_trie_from_string('''
+ self.read_flag_trie_from_string("""
Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
Ljava/lang/Object;->hashCode()I,blocked
-''')
- self.assertTrue("Duplicate signature: Ljava/lang/Object;->hashCode()I" in str(context.exception))
+""")
+ self.assertTrue('Duplicate signature: Ljava/lang/Object;->hashCode()I'
+ in str(context.exception))
def test_read_trie_missing_member(self):
with self.assertRaises(Exception) as context:
- self.read_flag_trie_from_string('''
+ self.read_flag_trie_from_string("""
Ljava/lang/Object,public-api,system-api,test-api
-''')
- self.assertTrue("Invalid signature: Ljava/lang/Object, does not identify a specific member" in str(context.exception))
+""")
+ self.assertTrue(
+ 'Invalid signature: Ljava/lang/Object, does not identify a specific member'
+ in str(context.exception))
def test_match(self):
- monolithic = self.read_signature_csv_from_string_as_dict('''
+ monolithic = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
-''')
- modular = self.read_signature_csv_from_string_as_dict('''
+""")
+ modular = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
-''')
+""")
mismatches = compare_signature_flags(monolithic, modular)
expected = []
self.assertEqual(expected, mismatches)
def test_mismatch_overlapping_flags(self):
- monolithic = self.read_signature_csv_from_string_as_dict('''
+ monolithic = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->toString()Ljava/lang/String;,public-api
-''')
- modular = self.read_signature_csv_from_string_as_dict('''
+""")
+ modular = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
-''')
+""")
mismatches = compare_signature_flags(monolithic, modular)
expected = [
(
@@ -263,14 +297,13 @@
]
self.assertEqual(expected, mismatches)
-
def test_mismatch_monolithic_blocked(self):
- monolithic = self.read_signature_csv_from_string_as_dict('''
+ monolithic = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
-''')
- modular = self.read_signature_csv_from_string_as_dict('''
+""")
+ modular = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
-''')
+""")
mismatches = compare_signature_flags(monolithic, modular)
expected = [
(
@@ -282,12 +315,12 @@
self.assertEqual(expected, mismatches)
def test_mismatch_modular_blocked(self):
- monolithic = self.read_signature_csv_from_string_as_dict('''
+ monolithic = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
-''')
- modular = self.read_signature_csv_from_string_as_dict('''
+""")
+ modular = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->toString()Ljava/lang/String;,blocked
-''')
+""")
mismatches = compare_signature_flags(monolithic, modular)
expected = [
(
@@ -300,9 +333,9 @@
def test_match_treat_missing_from_modular_as_blocked(self):
monolithic = self.read_signature_csv_from_string_as_dict('')
- modular = self.read_signature_csv_from_string_as_dict('''
+ modular = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->toString()Ljava/lang/String;,public-api,system-api,test-api
-''')
+""")
mismatches = compare_signature_flags(monolithic, modular)
expected = [
(
@@ -314,9 +347,9 @@
self.assertEqual(expected, mismatches)
def test_mismatch_treat_missing_from_modular_as_blocked(self):
- monolithic = self.read_signature_csv_from_string_as_dict('''
+ monolithic = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->hashCode()I,public-api,system-api,test-api
-''')
+""")
modular = {}
mismatches = compare_signature_flags(monolithic, modular)
expected = [
@@ -329,13 +362,14 @@
self.assertEqual(expected, mismatches)
def test_blocked_missing_from_modular(self):
- monolithic = self.read_signature_csv_from_string_as_dict('''
+ monolithic = self.read_signature_csv_from_string_as_dict("""
Ljava/lang/Object;->hashCode()I,blocked
-''')
+""")
modular = {}
mismatches = compare_signature_flags(monolithic, modular)
expected = []
self.assertEqual(expected, mismatches)
+#pylint: enable=line-too-long
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/sdk/Android.bp b/sdk/Android.bp
index 368c03a..0c9bf27 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -16,6 +16,7 @@
srcs: [
"bp.go",
"exports.go",
+ "member_type.go",
"sdk.go",
"update.go",
],
diff --git a/sdk/member_type.go b/sdk/member_type.go
new file mode 100644
index 0000000..ee27c86
--- /dev/null
+++ b/sdk/member_type.go
@@ -0,0 +1,164 @@
+// Copyright (C) 2021 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 (
+ "reflect"
+
+ "android/soong/android"
+ "github.com/google/blueprint/proptools"
+)
+
+// Contains information about the sdk properties that list sdk members by type, e.g.
+// Java_header_libs.
+type sdkMemberTypeListProperty struct {
+ // getter for the list of member names
+ getter func(properties interface{}) []string
+
+ // setter for the list of member names
+ setter func(properties interface{}, list []string)
+
+ // the type of member referenced in the list
+ memberType android.SdkMemberType
+
+ // the dependency tag used for items in this list that can be used to determine the memberType
+ // for a resolved dependency.
+ dependencyTag android.SdkMemberTypeDependencyTag
+}
+
+func (p *sdkMemberTypeListProperty) propertyName() string {
+ return p.memberType.SdkPropertyName()
+}
+
+// Cache of dynamically generated dynamicSdkMemberTypes objects. The key is the pointer
+// to a slice of SdkMemberType instances held in android.SdkMemberTypes.
+var dynamicSdkMemberTypesMap android.OncePer
+
+// A dynamically generated set of member list properties and associated structure type.
+type dynamicSdkMemberTypes struct {
+ // The dynamically generated structure type.
+ //
+ // Contains one []string exported field for each android.SdkMemberTypes. The name of the field
+ // is the exported form of the value returned by SdkMemberType.SdkPropertyName().
+ propertiesStructType reflect.Type
+
+ // Information about each of the member type specific list properties.
+ memberTypeListProperties []*sdkMemberTypeListProperty
+
+ memberTypeToProperty map[android.SdkMemberType]*sdkMemberTypeListProperty
+}
+
+func (d *dynamicSdkMemberTypes) createMemberTypeListProperties() interface{} {
+ return reflect.New(d.propertiesStructType).Interface()
+}
+
+func getDynamicSdkMemberTypes(registry *android.SdkMemberTypesRegistry) *dynamicSdkMemberTypes {
+
+ // Get a key that uniquely identifies the registry contents.
+ key := registry.UniqueOnceKey()
+
+ // Get the registered types.
+ registeredTypes := registry.RegisteredTypes()
+
+ // Get the cached value, creating new instance if necessary.
+ return dynamicSdkMemberTypesMap.Once(key, func() interface{} {
+ return createDynamicSdkMemberTypes(registeredTypes)
+ }).(*dynamicSdkMemberTypes)
+}
+
+// Create the dynamicSdkMemberTypes from the list of registered member types.
+//
+// A struct is created which contains one exported field per member type corresponding to
+// the SdkMemberType.SdkPropertyName() value.
+//
+// A list of sdkMemberTypeListProperty instances is created, one per member type that provides:
+// * a reference to the member type.
+// * a getter for the corresponding field in the properties struct.
+// * a dependency tag that identifies the member type of a resolved dependency.
+//
+func createDynamicSdkMemberTypes(sdkMemberTypes []android.SdkMemberType) *dynamicSdkMemberTypes {
+
+ var listProperties []*sdkMemberTypeListProperty
+ memberTypeToProperty := map[android.SdkMemberType]*sdkMemberTypeListProperty{}
+ var fields []reflect.StructField
+
+ // Iterate over the member types creating StructField and sdkMemberTypeListProperty objects.
+ nextFieldIndex := 0
+ for _, memberType := range sdkMemberTypes {
+
+ p := memberType.SdkPropertyName()
+
+ var getter func(properties interface{}) []string
+ var setter func(properties interface{}, list []string)
+ if memberType.RequiresBpProperty() {
+ // Create a dynamic exported field for the member type's property.
+ fields = append(fields, reflect.StructField{
+ Name: proptools.FieldNameForProperty(p),
+ Type: reflect.TypeOf([]string{}),
+ Tag: `android:"arch_variant"`,
+ })
+
+ // Copy the field index for use in the getter func as using the loop variable directly will
+ // cause all funcs to use the last value.
+ fieldIndex := nextFieldIndex
+ nextFieldIndex += 1
+
+ getter = func(properties interface{}) []string {
+ // The properties is expected to be of the following form (where
+ // <Module_types> is the name of an SdkMemberType.SdkPropertyName().
+ // properties *struct {<Module_types> []string, ....}
+ //
+ // Although it accesses the field by index the following reflection code is equivalent to:
+ // *properties.<Module_types>
+ //
+ list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string)
+ return list
+ }
+
+ setter = func(properties interface{}, list []string) {
+ // The properties is expected to be of the following form (where
+ // <Module_types> is the name of an SdkMemberType.SdkPropertyName().
+ // properties *struct {<Module_types> []string, ....}
+ //
+ // Although it accesses the field by index the following reflection code is equivalent to:
+ // *properties.<Module_types> = list
+ //
+ reflect.ValueOf(properties).Elem().Field(fieldIndex).Set(reflect.ValueOf(list))
+ }
+ }
+
+ // Create an sdkMemberTypeListProperty for the member type.
+ memberListProperty := &sdkMemberTypeListProperty{
+ getter: getter,
+ setter: setter,
+ memberType: memberType,
+
+ // Dependencies added directly from member properties are always exported.
+ dependencyTag: android.DependencyTagForSdkMemberType(memberType, true),
+ }
+
+ memberTypeToProperty[memberType] = memberListProperty
+ listProperties = append(listProperties, memberListProperty)
+ }
+
+ // Create a dynamic struct from the collated fields.
+ propertiesStructType := reflect.StructOf(fields)
+
+ return &dynamicSdkMemberTypes{
+ memberTypeListProperties: listProperties,
+ memberTypeToProperty: memberTypeToProperty,
+ propertiesStructType: propertiesStructType,
+ }
+}
diff --git a/sdk/sdk.go b/sdk/sdk.go
index b1c8aeb..6dea752 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -17,7 +17,6 @@
import (
"fmt"
"io"
- "reflect"
"strconv"
"github.com/google/blueprint"
@@ -50,7 +49,7 @@
// The dynamically generated information about the registered SdkMemberType
dynamicSdkMemberTypes *dynamicSdkMemberTypes
- // The dynamically created instance of the properties struct containing the sdk member
+ // The dynamically created instance of the properties struct containing the sdk member type
// list properties, e.g. java_libs.
dynamicMemberTypeListProperties interface{}
@@ -95,148 +94,6 @@
Prebuilt_visibility []string
}
-// Contains information about the sdk properties that list sdk members, e.g.
-// Java_header_libs.
-type sdkMemberListProperty struct {
- // getter for the list of member names
- getter func(properties interface{}) []string
-
- // setter for the list of member names
- setter func(properties interface{}, list []string)
-
- // the type of member referenced in the list
- memberType android.SdkMemberType
-
- // the dependency tag used for items in this list that can be used to determine the memberType
- // for a resolved dependency.
- dependencyTag android.SdkMemberTypeDependencyTag
-}
-
-func (p *sdkMemberListProperty) propertyName() string {
- return p.memberType.SdkPropertyName()
-}
-
-// Cache of dynamically generated dynamicSdkMemberTypes objects. The key is the pointer
-// to a slice of SdkMemberType instances held in android.SdkMemberTypes.
-var dynamicSdkMemberTypesMap android.OncePer
-
-// A dynamically generated set of member list properties and associated structure type.
-type dynamicSdkMemberTypes struct {
- // The dynamically generated structure type.
- //
- // Contains one []string exported field for each android.SdkMemberTypes. The name of the field
- // is the exported form of the value returned by SdkMemberType.SdkPropertyName().
- propertiesStructType reflect.Type
-
- // Information about each of the member type specific list properties.
- memberListProperties []*sdkMemberListProperty
-
- memberTypeToProperty map[android.SdkMemberType]*sdkMemberListProperty
-}
-
-func (d *dynamicSdkMemberTypes) createMemberListProperties() interface{} {
- return reflect.New(d.propertiesStructType).Interface()
-}
-
-func getDynamicSdkMemberTypes(registry *android.SdkMemberTypesRegistry) *dynamicSdkMemberTypes {
-
- // Get a key that uniquely identifies the registry contents.
- key := registry.UniqueOnceKey()
-
- // Get the registered types.
- registeredTypes := registry.RegisteredTypes()
-
- // Get the cached value, creating new instance if necessary.
- return dynamicSdkMemberTypesMap.Once(key, func() interface{} {
- return createDynamicSdkMemberTypes(registeredTypes)
- }).(*dynamicSdkMemberTypes)
-}
-
-// Create the dynamicSdkMemberTypes from the list of registered member types.
-//
-// A struct is created which contains one exported field per member type corresponding to
-// the SdkMemberType.SdkPropertyName() value.
-//
-// A list of sdkMemberListProperty instances is created, one per member type that provides:
-// * a reference to the member type.
-// * a getter for the corresponding field in the properties struct.
-// * a dependency tag that identifies the member type of a resolved dependency.
-//
-func createDynamicSdkMemberTypes(sdkMemberTypes []android.SdkMemberType) *dynamicSdkMemberTypes {
-
- var listProperties []*sdkMemberListProperty
- memberTypeToProperty := map[android.SdkMemberType]*sdkMemberListProperty{}
- var fields []reflect.StructField
-
- // Iterate over the member types creating StructField and sdkMemberListProperty objects.
- nextFieldIndex := 0
- for _, memberType := range sdkMemberTypes {
-
- p := memberType.SdkPropertyName()
-
- var getter func(properties interface{}) []string
- var setter func(properties interface{}, list []string)
- if memberType.RequiresBpProperty() {
- // Create a dynamic exported field for the member type's property.
- fields = append(fields, reflect.StructField{
- Name: proptools.FieldNameForProperty(p),
- Type: reflect.TypeOf([]string{}),
- Tag: `android:"arch_variant"`,
- })
-
- // Copy the field index for use in the getter func as using the loop variable directly will
- // cause all funcs to use the last value.
- fieldIndex := nextFieldIndex
- nextFieldIndex += 1
-
- getter = func(properties interface{}) []string {
- // The properties is expected to be of the following form (where
- // <Module_types> is the name of an SdkMemberType.SdkPropertyName().
- // properties *struct {<Module_types> []string, ....}
- //
- // Although it accesses the field by index the following reflection code is equivalent to:
- // *properties.<Module_types>
- //
- list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string)
- return list
- }
-
- setter = func(properties interface{}, list []string) {
- // The properties is expected to be of the following form (where
- // <Module_types> is the name of an SdkMemberType.SdkPropertyName().
- // properties *struct {<Module_types> []string, ....}
- //
- // Although it accesses the field by index the following reflection code is equivalent to:
- // *properties.<Module_types> = list
- //
- reflect.ValueOf(properties).Elem().Field(fieldIndex).Set(reflect.ValueOf(list))
- }
- }
-
- // Create an sdkMemberListProperty for the member type.
- memberListProperty := &sdkMemberListProperty{
- getter: getter,
- setter: setter,
- memberType: memberType,
-
- // Dependencies added directly from member properties are always exported.
- dependencyTag: android.DependencyTagForSdkMemberType(memberType, true),
- }
-
- memberTypeToProperty[memberType] = memberListProperty
- listProperties = append(listProperties, memberListProperty)
- }
-
- // Create a dynamic struct from the collated fields.
- propertiesStructType := reflect.StructOf(fields)
-
- return &dynamicSdkMemberTypes{
- memberListProperties: listProperties,
- memberTypeToProperty: memberTypeToProperty,
- propertiesStructType: propertiesStructType,
- }
-}
-
// 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 SdkModuleFactory() android.Module {
@@ -247,16 +104,16 @@
s := &sdk{}
s.properties.Module_exports = moduleExports
// Get the dynamic sdk member type data for the currently registered sdk member types.
- var registry *android.SdkMemberTypesRegistry
+ var typeRegistry *android.SdkMemberTypesRegistry
if moduleExports {
- registry = android.ModuleExportsMemberTypes
+ typeRegistry = android.ModuleExportsMemberTypes
} else {
- registry = android.SdkMemberTypes
+ typeRegistry = android.SdkMemberTypes
}
- s.dynamicSdkMemberTypes = getDynamicSdkMemberTypes(registry)
+ s.dynamicSdkMemberTypes = getDynamicSdkMemberTypes(typeRegistry)
// Create an instance of the dynamically created struct that contains all the
// properties for the member type specific list properties.
- s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberListProperties()
+ s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberTypeListProperties()
s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties)
// Make sure that the prebuilt visibility property is verified for errors.
@@ -280,11 +137,11 @@
return s
}
-func (s *sdk) memberListProperties() []*sdkMemberListProperty {
- return s.dynamicSdkMemberTypes.memberListProperties
+func (s *sdk) memberTypeListProperties() []*sdkMemberTypeListProperty {
+ return s.dynamicSdkMemberTypes.memberTypeListProperties
}
-func (s *sdk) memberListProperty(memberType android.SdkMemberType) *sdkMemberListProperty {
+func (s *sdk) memberTypeListProperty(memberType android.SdkMemberType) *sdkMemberTypeListProperty {
return s.dynamicSdkMemberTypes.memberTypeToProperty[memberType]
}
@@ -341,6 +198,19 @@
}}
}
+// newDependencyContext creates a new SdkDependencyContext for this sdk.
+func (s *sdk) newDependencyContext(mctx android.BottomUpMutatorContext) android.SdkDependencyContext {
+ return &dependencyContext{
+ BottomUpMutatorContext: mctx,
+ }
+}
+
+type dependencyContext struct {
+ android.BottomUpMutatorContext
+}
+
+var _ android.SdkDependencyContext = (*dependencyContext)(nil)
+
// RegisterPreDepsMutators registers pre-deps mutators to support modules implementing SdkAware
// interface and the sdk module type. This function has been made public to be called by tests
// outside of the sdk package
@@ -410,14 +280,15 @@
if s, ok := mctx.Module().(*sdk); ok {
// Add dependencies from enabled and non CommonOS variants to the sdk member variants.
if s.Enabled() && !s.IsCommonOSVariant() {
- for _, memberListProperty := range s.memberListProperties() {
+ ctx := s.newDependencyContext(mctx)
+ for _, memberListProperty := range s.memberTypeListProperties() {
if memberListProperty.getter == nil {
continue
}
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
if len(names) > 0 {
tag := memberListProperty.dependencyTag
- memberListProperty.memberType.AddDependencies(mctx, tag, names)
+ memberListProperty.memberType.AddDependencies(ctx, tag, names)
}
}
}
diff --git a/sdk/update.go b/sdk/update.go
index 1cd8f13..96a6e69 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -251,7 +251,7 @@
}
var members []*sdkMember
- for _, memberListProperty := range s.memberListProperties() {
+ for _, memberListProperty := range s.memberTypeListProperties() {
membersOfType := byType[memberListProperty.memberType]
members = append(members, membersOfType...)
}
@@ -667,7 +667,7 @@
staticProperties := &snapshotModuleStaticProperties{
Compile_multilib: sdkVariant.multilibUsages.String(),
}
- dynamicProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
+ dynamicProperties := s.dynamicSdkMemberTypes.createMemberTypeListProperties()
combinedProperties := &combinedSnapshotModuleProperties{
sdkVariant: sdkVariant,
@@ -687,7 +687,7 @@
}
combined := sdkVariantToCombinedProperties[memberVariantDep.sdkVariant]
- memberListProperty := s.memberListProperty(memberVariantDep.memberType)
+ memberListProperty := s.memberTypeListProperty(memberVariantDep.memberType)
memberName := ctx.OtherModuleName(memberVariantDep.variant)
if memberListProperty.getter == nil {
@@ -717,7 +717,7 @@
}
// Extract the common members, removing them from the original properties.
- commonDynamicProperties := s.dynamicSdkMemberTypes.createMemberListProperties()
+ commonDynamicProperties := s.dynamicSdkMemberTypes.createMemberTypeListProperties()
extractor := newCommonValueExtractor(commonDynamicProperties)
extractCommonProperties(ctx, extractor, commonDynamicProperties, propertyContainers)
@@ -750,7 +750,7 @@
}
dynamicMemberTypeListProperties := combined.dynamicProperties
- for _, memberListProperty := range s.memberListProperties() {
+ for _, memberListProperty := range s.memberTypeListProperties() {
if memberListProperty.getter == nil {
continue
}
diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh
index 76b2ee9..b37a7f8 100755
--- a/tests/bootstrap_test.sh
+++ b/tests/bootstrap_test.sh
@@ -144,7 +144,7 @@
run_soong
local ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
- local glob_deps_file=out/soong/.bootstrap/globs/0.d
+ local glob_deps_file=out/soong/globs/build/0.d
if [ -e "$glob_deps_file" ]; then
fail "Glob deps file unexpectedly written on first build"
@@ -607,12 +607,36 @@
function test_dump_json_module_graph() {
setup
- SOONG_DUMP_JSON_MODULE_GRAPH="$MOCK_TOP/modules.json" run_soong
- if [[ ! -r "$MOCK_TOP/modules.json" ]]; then
+ GENERATE_JSON_MODULE_GRAPH=1 run_soong
+ if [[ ! -r "out/soong//module-graph.json" ]]; then
fail "JSON file was not created"
fi
}
+function test_json_module_graph_back_and_forth_null_build() {
+ setup
+
+ run_soong
+ local ninja_mtime1=$(stat -c "%y" out/soong/build.ninja)
+
+ GENERATE_JSON_MODULE_GRAPH=1 run_soong
+ local json_mtime1=$(stat -c "%y" out/soong/module-graph.json)
+
+ run_soong
+ local ninja_mtime2=$(stat -c "%y" out/soong/build.ninja)
+ if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then
+ fail "Output Ninja file changed after writing JSON module graph"
+ fi
+
+ GENERATE_JSON_MODULE_GRAPH=1 run_soong
+ local json_mtime2=$(stat -c "%y" out/soong/module-graph.json)
+ if [[ "$json_mtime1" != "$json_mtime2" ]]; then
+ fail "JSON module graph file changed after writing Ninja file"
+ fi
+
+}
+
+
function test_bp2build_bazel_workspace_structure {
setup
@@ -757,6 +781,7 @@
test_glob_during_bootstrapping
test_soong_build_rerun_iff_environment_changes
test_dump_json_module_graph
+test_json_module_graph_back_and_forth_null_build
test_write_to_source_tree
test_bp2build_smoke
test_bp2build_generates_marker_file
diff --git a/ui/build/config.go b/ui/build/config.go
index 956406d..6de7a05 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -739,6 +739,20 @@
return filepath.Join(c.OutDir(), "soong")
}
+func (c *configImpl) PrebuiltOS() string {
+ switch runtime.GOOS {
+ case "linux":
+ return "linux-x86"
+ case "darwin":
+ return "darwin-x86"
+ default:
+ panic("Unknown GOOS")
+ }
+}
+func (c *configImpl) HostToolDir() string {
+ return filepath.Join(c.SoongOutDir(), "host", c.PrebuiltOS(), "bin")
+}
+
func (c *configImpl) MainNinjaFile() string {
return shared.JoinPath(c.SoongOutDir(), "build.ninja")
}
@@ -747,6 +761,10 @@
return shared.JoinPath(c.SoongOutDir(), ".bootstrap/bp2build_workspace_marker")
}
+func (c *configImpl) ModuleGraphFile() string {
+ return shared.JoinPath(c.SoongOutDir(), "module-graph.json")
+}
+
func (c *configImpl) TempDir() string {
return shared.TempDirForOutDir(c.SoongOutDir())
}
@@ -919,7 +937,7 @@
return mixedBuild
} else if c.Environment().IsEnvTrue("GENERATE_BAZEL_FILES") {
return generateBuildFiles
- } else if v, ok := c.Environment().Get("SOONG_DUMP_JSON_MODULE_GRAPH"); ok && v != "" {
+ } else if c.Environment().IsEnvTrue("GENERATE_JSON_MODULE_GRAPH") {
return generateJsonModuleGraph
} else {
return noBazel
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 8ef8c74..a627dae 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -71,17 +71,22 @@
// A tiny struct used to tell Blueprint that it's in bootstrap mode. It would
// probably be nicer to use a flag in bootstrap.Args instead.
type BlueprintConfig struct {
- buildDir string
- ninjaBuildDir string
+ toolDir string
+ soongOutDir string
+ outDir string
debugCompilation bool
}
-func (c BlueprintConfig) BuildDir() string {
- return c.buildDir
+func (c BlueprintConfig) HostToolDir() string {
+ return c.toolDir
}
-func (c BlueprintConfig) NinjaBuildDir() string {
- return c.ninjaBuildDir
+func (c BlueprintConfig) SoongOutDir() string {
+ return c.soongOutDir
+}
+
+func (c BlueprintConfig) OutDir() string {
+ return c.outDir
}
func (c BlueprintConfig) DebugCompilation() bool {
@@ -117,6 +122,7 @@
bootstrapGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.ninja")
bp2buildGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.bp2build.ninja")
+ moduleGraphGlobFile := shared.JoinPath(config.SoongOutDir(), ".bootstrap/build-globs.modulegraph.ninja")
// The glob .ninja files are subninja'd. However, they are generated during
// the build itself so we write an empty file so that the subninja doesn't
@@ -127,16 +133,14 @@
args.RunGoTests = !config.skipSoongTests
args.UseValidations = true // Use validations to depend on tests
- args.BuildDir = config.SoongOutDir()
- args.NinjaBuildDir = config.OutDir()
- args.TopFile = "Android.bp"
+ args.SoongOutDir = config.SoongOutDir()
+ args.OutDir = config.OutDir()
args.ModuleListFile = filepath.Join(config.FileListDir(), "Android.bp.list")
args.OutFile = shared.JoinPath(config.SoongOutDir(), ".bootstrap/build.ninja")
// The primary builder (aka soong_build) will use bootstrapGlobFile as the globFile to generate build.ninja(.d)
// Building soong_build does not require a glob file
// Using "" instead of "<soong_build_glob>.ninja" will ensure that an unused glob file is not written to out/soong/.bootstrap during StagePrimary
args.Subninjas = []string{bootstrapGlobFile, bp2buildGlobFile}
- args.GeneratingPrimaryBuilder = true
args.EmptyNinjaFile = config.EmptyNinjaFile()
args.DelveListen = os.Getenv("SOONG_DELVE")
@@ -152,7 +156,7 @@
}
soongBuildArgs := []string{
- "--globListDir", "globs",
+ "--globListDir", "build",
"--globFile", bootstrapGlobFile,
}
@@ -168,7 +172,7 @@
bp2buildArgs := []string{
"--bp2build_marker", config.Bp2BuildMarkerFile(),
- "--globListDir", "globs.bp2build",
+ "--globListDir", "bp2build",
"--globFile", bp2buildGlobFile,
}
@@ -181,19 +185,39 @@
Outputs: []string{config.Bp2BuildMarkerFile()},
Args: bp2buildArgs,
}
+
+ moduleGraphArgs := []string{
+ "--module_graph_file", config.ModuleGraphFile(),
+ "--globListDir", "modulegraph",
+ "--globFile", moduleGraphGlobFile,
+ }
+
+ moduleGraphArgs = append(moduleGraphArgs, commonArgs...)
+ moduleGraphArgs = append(moduleGraphArgs, environmentArgs(config, ".modulegraph")...)
+ moduleGraphArgs = append(moduleGraphArgs, "Android.bp")
+
+ moduleGraphInvocation := bootstrap.PrimaryBuilderInvocation{
+ Inputs: []string{"Android.bp"},
+ Outputs: []string{config.ModuleGraphFile()},
+ Args: moduleGraphArgs,
+ }
+
args.PrimaryBuilderInvocations = []bootstrap.PrimaryBuilderInvocation{
bp2buildInvocation,
mainSoongBuildInvocation,
+ moduleGraphInvocation,
}
blueprintCtx := blueprint.NewContext()
blueprintCtx.SetIgnoreUnknownModuleTypes(true)
blueprintConfig := BlueprintConfig{
- buildDir: config.SoongOutDir(),
- ninjaBuildDir: config.OutDir(),
+ soongOutDir: config.SoongOutDir(),
+ toolDir: config.HostToolDir(),
+ outDir: config.OutDir(),
debugCompilation: os.Getenv("SOONG_DELVE") != "",
}
+ args.EmptyNinjaFile = false
bootstrapDeps := bootstrap.RunBlueprint(args, blueprintCtx, blueprintConfig)
err := deptools.WriteDepFile(bootstrapDepFile, args.OutFile, bootstrapDeps)
if err != nil {
@@ -264,7 +288,7 @@
}
}()
- runMicrofactory(ctx, config, ".bootstrap/bpglob", "github.com/google/blueprint/bootstrap/bpglob",
+ runMicrofactory(ctx, config, filepath.Join(config.HostToolDir(), "bpglob"), "github.com/google/blueprint/bootstrap/bpglob",
map[string]string{"github.com/google/blueprint": "build/blueprint"})
ninja := func(name, ninjaFile string, targets ...string) {
@@ -307,6 +331,8 @@
if config.bazelBuildMode() == generateBuildFiles {
target = config.Bp2BuildMarkerFile()
+ } else if config.bazelBuildMode() == generateJsonModuleGraph {
+ target = config.ModuleGraphFile()
} else {
// This build generates <builddir>/build.ninja, which is used later by build/soong/ui/build/build.go#Build().
target = config.MainNinjaFile()
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 57ceaba..f9a60b6 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -51,7 +51,6 @@
executable := config.PrebuiltBuildTool("ninja")
commonArgs := []string{}
- commonArgs = append(commonArgs, config.NinjaArgs()...)
commonArgs = append(commonArgs, "-f", config.CombinedNinjaFile())
args := append(commonArgs, "-t", "targets", "rule")