Merge "Remove env config fetcher code"
diff --git a/OWNERS b/OWNERS
index 0234f27..9221d3e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -10,10 +10,12 @@
delmerico@google.com
dwillemsen@google.com
eakammer@google.com
+jihoonkang@google.com
jobredeaux@google.com
joeo@google.com
juu@google.com
lamontjones@google.com
+mrziwang@google.com
spandandas@google.com
tradical@google.com
usta@google.com
diff --git a/README.md b/README.md
index 70311cb..2d8f0af 100644
--- a/README.md
+++ b/README.md
@@ -565,6 +565,12 @@
by all of the vendor's other modules using the normal namespace and visibility
rules.
+`soongConfigTraceMutator` enables modules affected by soong config variables to
+write outputs into a hashed directory path. It does this by recording accesses
+to soong config variables on each module, and then accumulating records of each
+module's all dependencies. `m soong_config_trace` builds information about
+hashes to `$OUT_DIR/soong/soong_config_trace.json`.
+
## Build logic
The build logic is written in Go using the
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 751a4cb..6405e9f 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -761,6 +761,11 @@
// aidl
"aidl",
"libaidl-common",
+
+ // java_resources containing only a single filegroup
+ "libauto_value_plugin",
+ "auto_value_plugin_resources",
+ "auto_value_extension",
}
Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -835,7 +840,6 @@
"libprotobuf-internal-python-srcs", // TODO(b/210751803), we don't handle path property for filegroups
"libprotobuf-java-full", // TODO(b/210751803), we don't handle path property for filegroups
"libprotobuf-java-util-full", // TODO(b/210751803), we don't handle path property for filegroups
- "auto_value_plugin_resources", // TODO(b/210751803), we don't handle path property for filegroups
// go deps:
"analyze_bcpf", // depends on bpmodify a blueprint_go_binary.
diff --git a/android/config.go b/android/config.go
index d148012..bed57e3 100644
--- a/android/config.go
+++ b/android/config.go
@@ -80,9 +80,10 @@
type CmdArgs struct {
bootstrap.Args
- RunGoTests bool
- OutDir string
- SoongOutDir string
+ RunGoTests bool
+ OutDir string
+ SoongOutDir string
+ SoongVariables string
SymlinkForestMarker string
Bp2buildMarker string
@@ -491,7 +492,7 @@
func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) {
// Make a config with default options.
config := &config{
- ProductVariablesFileName: filepath.Join(cmdArgs.SoongOutDir, productVariablesFileName),
+ ProductVariablesFileName: cmdArgs.SoongVariables,
env: availableEnv,
diff --git a/android/filegroup.go b/android/filegroup.go
index f30ee51..c042ff1 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -177,6 +177,17 @@
}
}
+type FileGroupPath interface {
+ GetPath(ctx TopDownMutatorContext) string
+}
+
+func (fg *fileGroup) GetPath(ctx TopDownMutatorContext) string {
+ if fg.properties.Path != nil {
+ return *fg.properties.Path
+ }
+ return ""
+}
+
type fileGroupProperties struct {
// srcs lists files that will be included in this filegroup
Srcs []string `android:"path"`
@@ -207,6 +218,7 @@
BazelModuleBase
DefaultableModuleBase
FileGroupAsLibrary
+ FileGroupPath
properties fileGroupProperties
srcs Paths
}
@@ -214,6 +226,7 @@
var _ MixedBuildBuildable = (*fileGroup)(nil)
var _ SourceFileProducer = (*fileGroup)(nil)
var _ FileGroupAsLibrary = (*fileGroup)(nil)
+var _ FileGroupPath = (*fileGroup)(nil)
// filegroup contains a list of files that are referenced by other modules
// properties (such as "srcs") using the syntax ":<name>". filegroup are
diff --git a/android/module.go b/android/module.go
index 604ba24..98084f3 100644
--- a/android/module.go
+++ b/android/module.go
@@ -15,6 +15,9 @@
package android
import (
+ "crypto/md5"
+ "encoding/hex"
+ "encoding/json"
"fmt"
"net/url"
"os"
@@ -714,6 +717,31 @@
return l[:k+1]
}
+// soongConfigTrace holds all references to VendorVars. Uses []string for blueprint:"mutated"
+type soongConfigTrace struct {
+ Bools []string `json:",omitempty"`
+ Strings []string `json:",omitempty"`
+ IsSets []string `json:",omitempty"`
+}
+
+func (c *soongConfigTrace) isEmpty() bool {
+ return len(c.Bools) == 0 && len(c.Strings) == 0 && len(c.IsSets) == 0
+}
+
+// Returns hash of serialized trace records (empty string if there's no trace recorded)
+func (c *soongConfigTrace) hash() string {
+ // Use MD5 for speed. We don't care collision or preimage attack
+ if c.isEmpty() {
+ return ""
+ }
+ j, err := json.Marshal(c)
+ if err != nil {
+ panic(fmt.Errorf("json marshal of %#v failed: %#v", *c, err))
+ }
+ hash := md5.Sum(j)
+ return hex.EncodeToString(hash[:])
+}
+
type nameProperties struct {
// The name of the module. Must be unique across all modules.
Name *string
@@ -958,6 +986,10 @@
// Bazel conversion status
BazelConversionStatus BazelConversionStatus `blueprint:"mutated"`
+
+ // SoongConfigTrace records accesses to VendorVars (soong_config)
+ SoongConfigTrace soongConfigTrace `blueprint:"mutated"`
+ SoongConfigTraceHash string `blueprint:"mutated"`
}
// CommonAttributes represents the common Bazel attributes from which properties
@@ -3160,6 +3192,10 @@
return m.bp.ModuleSubDir()
}
+func (m *moduleContext) ModuleSoongConfigHash() string {
+ return m.module.base().commonProperties.SoongConfigTraceHash
+}
+
func (b *baseModuleContext) Target() Target {
return b.target
}
@@ -3744,6 +3780,8 @@
func init() {
RegisterParallelSingletonType("buildtarget", BuildTargetSingleton)
+ RegisterParallelSingletonType("soongconfigtrace", soongConfigTraceSingletonFunc)
+ FinalDepsMutators(registerSoongConfigTraceMutator)
}
func BuildTargetSingleton() Singleton {
@@ -3925,3 +3963,54 @@
}
return d.depSet.ToList().(InstallPaths)
}
+
+func registerSoongConfigTraceMutator(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("soongconfigtrace", soongConfigTraceMutator).Parallel()
+}
+
+// soongConfigTraceMutator accumulates recorded soong_config trace from children. Also it normalizes
+// SoongConfigTrace to make it consistent.
+func soongConfigTraceMutator(ctx BottomUpMutatorContext) {
+ trace := &ctx.Module().base().commonProperties.SoongConfigTrace
+ ctx.VisitDirectDeps(func(m Module) {
+ childTrace := &m.base().commonProperties.SoongConfigTrace
+ trace.Bools = append(trace.Bools, childTrace.Bools...)
+ trace.Strings = append(trace.Strings, childTrace.Strings...)
+ trace.IsSets = append(trace.IsSets, childTrace.IsSets...)
+ })
+ trace.Bools = SortedUniqueStrings(trace.Bools)
+ trace.Strings = SortedUniqueStrings(trace.Strings)
+ trace.IsSets = SortedUniqueStrings(trace.IsSets)
+
+ ctx.Module().base().commonProperties.SoongConfigTraceHash = trace.hash()
+}
+
+// soongConfigTraceSingleton writes a map from each module's config hash value to trace data.
+func soongConfigTraceSingletonFunc() Singleton {
+ return &soongConfigTraceSingleton{}
+}
+
+type soongConfigTraceSingleton struct {
+}
+
+func (s *soongConfigTraceSingleton) GenerateBuildActions(ctx SingletonContext) {
+ outFile := PathForOutput(ctx, "soong_config_trace.json")
+
+ traces := make(map[string]*soongConfigTrace)
+ ctx.VisitAllModules(func(module Module) {
+ trace := &module.base().commonProperties.SoongConfigTrace
+ if !trace.isEmpty() {
+ hash := module.base().commonProperties.SoongConfigTraceHash
+ traces[hash] = trace
+ }
+ })
+
+ j, err := json.Marshal(traces)
+ if err != nil {
+ ctx.Errorf("json marshal to %q failed: %#v", outFile, err)
+ return
+ }
+
+ WriteFileRule(ctx, outFile, string(j))
+ ctx.Phony("soong_config_trace", outFile)
+}
diff --git a/android/paths.go b/android/paths.go
index eaa6a8d..0f3d972 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1475,7 +1475,11 @@
}
func pathForModuleOut(ctx ModuleOutPathContext) OutputPath {
- return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
+ soongConfigHash := ""
+ if i, ok := ctx.(interface{ ModuleSoongConfigHash() string }); ok {
+ soongConfigHash = i.ModuleSoongConfigHash()
+ }
+ return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir(), soongConfigHash)
}
// PathForModuleOut returns a Path representing the paths... under the module's
diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go
index 5fa6012..0246a08 100644
--- a/android/soong_config_modules.go
+++ b/android/soong_config_modules.go
@@ -421,6 +421,57 @@
}).(map[string]blueprint.ModuleFactory)
}
+// tracingConfig is a wrapper to soongconfig.SoongConfig which records all accesses to SoongConfig.
+type tracingConfig struct {
+ config soongconfig.SoongConfig
+ boolSet map[string]bool
+ stringSet map[string]string
+ isSetSet map[string]bool
+}
+
+func (c *tracingConfig) Bool(name string) bool {
+ c.boolSet[name] = c.config.Bool(name)
+ return c.boolSet[name]
+}
+
+func (c *tracingConfig) String(name string) string {
+ c.stringSet[name] = c.config.String(name)
+ return c.stringSet[name]
+}
+
+func (c *tracingConfig) IsSet(name string) bool {
+ c.isSetSet[name] = c.config.IsSet(name)
+ return c.isSetSet[name]
+}
+
+func (c *tracingConfig) getTrace() soongConfigTrace {
+ ret := soongConfigTrace{}
+
+ for k, v := range c.boolSet {
+ ret.Bools = append(ret.Bools, fmt.Sprintf("%q:%t", k, v))
+ }
+ for k, v := range c.stringSet {
+ ret.Strings = append(ret.Strings, fmt.Sprintf("%q:%q", k, v))
+ }
+ for k, v := range c.isSetSet {
+ ret.IsSets = append(ret.IsSets, fmt.Sprintf("%q:%t", k, v))
+ }
+
+ return ret
+}
+
+func newTracingConfig(config soongconfig.SoongConfig) *tracingConfig {
+ c := tracingConfig{
+ config: config,
+ boolSet: make(map[string]bool),
+ stringSet: make(map[string]string),
+ isSetSet: make(map[string]bool),
+ }
+ return &c
+}
+
+var _ soongconfig.SoongConfig = (*tracingConfig)(nil)
+
// configModuleFactory takes an existing soongConfigModuleFactory and a
// ModuleType to create a new ModuleFactory that uses a custom loadhook.
func configModuleFactory(factory blueprint.ModuleFactory, moduleType *soongconfig.ModuleType, bp2build bool) blueprint.ModuleFactory {
@@ -485,8 +536,8 @@
// conditional on Soong config variables by reading the product
// config variables from Make.
AddLoadHook(module, func(ctx LoadHookContext) {
- config := ctx.Config().VendorConfig(moduleType.ConfigNamespace)
- newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, config)
+ tracingConfig := newTracingConfig(ctx.Config().VendorConfig(moduleType.ConfigNamespace))
+ newProps, err := soongconfig.PropertiesToApply(moduleType, conditionalProps, tracingConfig)
if err != nil {
ctx.ModuleErrorf("%s", err)
return
@@ -494,6 +545,8 @@
for _, ps := range newProps {
ctx.AppendProperties(ps)
}
+
+ module.(Module).base().commonProperties.SoongConfigTrace = tracingConfig.getTrace()
})
}
return module, props
diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go
index cab3e2d..79bdeb8 100644
--- a/android/soong_config_modules_test.go
+++ b/android/soong_config_modules_test.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"testing"
)
@@ -34,7 +35,8 @@
type soongConfigTestModule struct {
ModuleBase
DefaultableModuleBase
- props soongConfigTestModuleProperties
+ props soongConfigTestModuleProperties
+ outputPath ModuleOutPath
}
type soongConfigTestModuleProperties struct {
@@ -49,7 +51,9 @@
return m
}
-func (t soongConfigTestModule) GenerateAndroidBuildActions(ModuleContext) {}
+func (t *soongConfigTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ t.outputPath = PathForModuleOut(ctx, "test")
+}
var prepareForSoongConfigTestModule = FixtureRegisterWithContext(func(ctx RegistrationContext) {
ctx.RegisterModuleType("test_defaults", soongConfigTestDefaultsModuleFactory)
@@ -503,3 +507,197 @@
})
}
}
+
+func TestSoongConfigModuleTrace(t *testing.T) {
+ bp := `
+ soong_config_module_type {
+ name: "acme_test",
+ module_type: "test",
+ config_namespace: "acme",
+ variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
+ bool_variables: ["feature2", "unused_feature", "always_true"],
+ value_variables: ["size", "unused_size"],
+ properties: ["cflags", "srcs", "defaults"],
+ }
+
+ soong_config_module_type {
+ name: "acme_test_defaults",
+ module_type: "test_defaults",
+ config_namespace: "acme",
+ variables: ["board", "feature1", "FEATURE3", "unused_string_var"],
+ bool_variables: ["feature2", "unused_feature", "always_true"],
+ value_variables: ["size", "unused_size"],
+ properties: ["cflags", "srcs", "defaults"],
+ }
+
+ soong_config_string_variable {
+ name: "board",
+ values: ["soc_a", "soc_b", "soc_c"],
+ }
+
+ soong_config_string_variable {
+ name: "unused_string_var",
+ values: ["a", "b"],
+ }
+
+ soong_config_bool_variable {
+ name: "feature1",
+ }
+
+ soong_config_bool_variable {
+ name: "FEATURE3",
+ }
+
+ test_defaults {
+ name: "test_defaults",
+ cflags: ["DEFAULT"],
+ }
+
+ test {
+ name: "normal",
+ defaults: ["test_defaults"],
+ }
+
+ acme_test {
+ name: "board_1",
+ defaults: ["test_defaults"],
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ },
+ },
+ }
+
+ acme_test {
+ name: "board_2",
+ defaults: ["test_defaults"],
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ },
+ },
+ }
+
+ acme_test {
+ name: "size",
+ defaults: ["test_defaults"],
+ soong_config_variables: {
+ size: {
+ cflags: ["-DSIZE=%s"],
+ },
+ },
+ }
+
+ acme_test {
+ name: "board_and_size",
+ defaults: ["test_defaults"],
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ },
+ size: {
+ cflags: ["-DSIZE=%s"],
+ },
+ },
+ }
+
+ acme_test_defaults {
+ name: "board_defaults",
+ soong_config_variables: {
+ board: {
+ soc_a: {
+ cflags: ["-DSOC_A"],
+ },
+ },
+ },
+ }
+
+ acme_test_defaults {
+ name: "size_defaults",
+ soong_config_variables: {
+ size: {
+ cflags: ["-DSIZE=%s"],
+ },
+ },
+ }
+
+ test {
+ name: "board_and_size_with_defaults",
+ defaults: ["board_defaults", "size_defaults"],
+ }
+ `
+
+ fixtureForVendorVars := func(vars map[string]map[string]string) FixturePreparer {
+ return FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+ variables.VendorVars = vars
+ })
+ }
+
+ preparer := fixtureForVendorVars(map[string]map[string]string{
+ "acme": {
+ "board": "soc_a",
+ "size": "42",
+ "feature1": "true",
+ "feature2": "false",
+ // FEATURE3 unset
+ "unused_feature": "true", // unused
+ "unused_size": "1", // unused
+ "unused_string_var": "a", // unused
+ "always_true": "true",
+ },
+ })
+
+ t.Run("soong config trace hash", func(t *testing.T) {
+ result := GroupFixturePreparers(
+ preparer,
+ PrepareForTestWithDefaults,
+ PrepareForTestWithSoongConfigModuleBuildComponents,
+ prepareForSoongConfigTestModule,
+ FixtureRegisterWithContext(func(ctx RegistrationContext) {
+ ctx.FinalDepsMutators(registerSoongConfigTraceMutator)
+ }),
+ FixtureWithRootAndroidBp(bp),
+ ).RunTest(t)
+
+ // Hashes of modules not using soong config should be empty
+ normal := result.ModuleForTests("normal", "").Module().(*soongConfigTestModule)
+ AssertDeepEquals(t, "normal hash", normal.base().commonProperties.SoongConfigTraceHash, "")
+ AssertDeepEquals(t, "normal hash out", normal.outputPath.RelativeToTop().String(), "out/soong/.intermediates/normal/test")
+
+ board1 := result.ModuleForTests("board_1", "").Module().(*soongConfigTestModule)
+ board2 := result.ModuleForTests("board_2", "").Module().(*soongConfigTestModule)
+ size := result.ModuleForTests("size", "").Module().(*soongConfigTestModule)
+
+ // Trace mutator sets soong config trace hash correctly
+ board1Hash := board1.base().commonProperties.SoongConfigTrace.hash()
+ board1Output := board1.outputPath.RelativeToTop().String()
+ AssertDeepEquals(t, "board hash calc", board1Hash, board1.base().commonProperties.SoongConfigTraceHash)
+ AssertDeepEquals(t, "board hash path", board1Output, filepath.Join("out/soong/.intermediates/board_1", board1Hash, "test"))
+
+ sizeHash := size.base().commonProperties.SoongConfigTrace.hash()
+ sizeOutput := size.outputPath.RelativeToTop().String()
+ AssertDeepEquals(t, "size hash calc", sizeHash, size.base().commonProperties.SoongConfigTraceHash)
+ AssertDeepEquals(t, "size hash path", sizeOutput, filepath.Join("out/soong/.intermediates/size", sizeHash, "test"))
+
+ // Trace should be identical for modules using the same set of variables
+ AssertDeepEquals(t, "board trace", board1.base().commonProperties.SoongConfigTrace, board2.base().commonProperties.SoongConfigTrace)
+ AssertDeepEquals(t, "board hash", board1.base().commonProperties.SoongConfigTraceHash, board2.base().commonProperties.SoongConfigTraceHash)
+
+ // Trace hash should be different for different sets of soong variables
+ AssertBoolEquals(t, "board hash not equal to size hash", board1.base().commonProperties.SoongConfigTraceHash == size.commonProperties.SoongConfigTraceHash, false)
+
+ boardSize := result.ModuleForTests("board_and_size", "").Module().(*soongConfigTestModule)
+ boardSizeDefaults := result.ModuleForTests("board_and_size_with_defaults", "").Module()
+
+ // Trace should propagate
+ AssertDeepEquals(t, "board_size hash calc", boardSize.base().commonProperties.SoongConfigTrace.hash(), boardSize.base().commonProperties.SoongConfigTraceHash)
+ AssertDeepEquals(t, "board_size trace", boardSize.base().commonProperties.SoongConfigTrace, boardSizeDefaults.base().commonProperties.SoongConfigTrace)
+ AssertDeepEquals(t, "board_size hash", boardSize.base().commonProperties.SoongConfigTraceHash, boardSizeDefaults.base().commonProperties.SoongConfigTraceHash)
+ })
+}
diff --git a/android/test_asserts.go b/android/test_asserts.go
index 4143f15..5cc7e4a 100644
--- a/android/test_asserts.go
+++ b/android/test_asserts.go
@@ -17,6 +17,7 @@
import (
"fmt"
"reflect"
+ "regexp"
"strings"
"testing"
)
@@ -137,6 +138,20 @@
}
}
+// AssertStringMatches checks if the string matches the given regular expression. If it does not match,
+// then an error is reported with the supplied message including a reason for why it failed.
+func AssertStringMatches(t *testing.T, message, s, expectedRex string) {
+ t.Helper()
+ ok, err := regexp.MatchString(expectedRex, s)
+ if err != nil {
+ t.Fatalf("regexp failure trying to match %s against `%s` expression: %s", s, expectedRex, err)
+ return
+ }
+ if !ok {
+ t.Errorf("%s does not match regular expression %s", s, expectedRex)
+ }
+}
+
// AssertStringListContains checks if the list of strings contains the expected string. If it does
// not then it reports an error prefixed with the supplied message and including a reason for why it
// failed.
diff --git a/apex/apex.go b/apex/apex.go
index 1c79463..f49492e 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1871,14 +1871,17 @@
}); ok {
af.overriddenPackageName = app.OverriddenManifestPackageName()
}
- apexFiles := []apexFile{af}
+
+ apexFiles := []apexFile{}
if allowlist := aapp.PrivAppAllowlist(); allowlist.Valid() {
dirInApex := filepath.Join("etc", "permissions")
- privAppAllowlist := newApexFile(ctx, allowlist.Path(), aapp.BaseModuleName()+"privapp", dirInApex, etc, aapp)
+ privAppAllowlist := newApexFile(ctx, allowlist.Path(), aapp.BaseModuleName()+"_privapp", dirInApex, etc, aapp)
apexFiles = append(apexFiles, privAppAllowlist)
}
+ apexFiles = append(apexFiles, af)
+
return apexFiles
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 2dad22b..38e24e8 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -6305,6 +6305,18 @@
// ... and not directly inside the APEX
ensureNotContains(t, copyCmds, "image.apex/lib64/"+jni+".so")
}
+
+ apexBundle := module.Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, ctx, apexBundle)
+ var builder strings.Builder
+ data.Custom(&builder, apexBundle.Name(), "TARGET_", "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_MODULE := AppFooPriv.myapex")
+ ensureContains(t, androidMk, "LOCAL_MODULE := AppFoo.myapex")
+ ensureMatches(t, androidMk, "LOCAL_SOONG_INSTALLED_MODULE := \\S+AppFooPriv.apk")
+ ensureMatches(t, androidMk, "LOCAL_SOONG_INSTALLED_MODULE := \\S+AppFoo.apk")
+ ensureMatches(t, androidMk, "LOCAL_SOONG_INSTALL_PAIRS := \\S+AppFooPriv.apk")
+ ensureContains(t, androidMk, "LOCAL_SOONG_INSTALL_PAIRS := privapp_allowlist_com.android.AppFooPriv.xml:$(PRODUCT_OUT)/apex/myapex/etc/permissions/privapp_allowlist_com.android.AppFooPriv.xml")
}
func TestApexWithAppImportBuildId(t *testing.T) {
diff --git a/bp2build/java_library_conversion_test.go b/bp2build/java_library_conversion_test.go
index 60766f4..fd92e95 100644
--- a/bp2build/java_library_conversion_test.go
+++ b/bp2build/java_library_conversion_test.go
@@ -826,3 +826,43 @@
},
})
}
+
+func TestJavaLibraryJavaResourcesSingleFilegroup(t *testing.T) {
+ runJavaLibraryTestCaseWithRegistrationCtxFunc(t, Bp2buildTestCase{
+ Filesystem: map[string]string{
+ "res/a.res": "",
+ "res/b.res": "",
+ "res/dir1/b.res": "",
+ },
+ Description: "java_library",
+ Blueprint: `java_library {
+ name: "java-lib-1",
+ srcs: ["a.java"],
+ java_resources: [":filegroup1"],
+ bazel_module: { bp2build_available: true },
+}
+
+filegroup {
+ name: "filegroup1",
+ path: "foo",
+ srcs: ["foo/a", "foo/b"],
+}
+
+`,
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("java_library", "java-lib-1", AttrNameToString{
+ "srcs": `["a.java"]`,
+ "resources": `[":filegroup1"]`,
+ "resource_strip_prefix": `"foo"`,
+ }),
+ MakeNeverlinkDuplicateTarget("java_library", "java-lib-1"),
+ MakeBazelTargetNoRestrictions("filegroup", "filegroup1", AttrNameToString{
+ "srcs": `[
+ "foo/a",
+ "foo/b",
+ ]`}),
+ },
+ }, func(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+ })
+}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index cf6c1c7..e006c9d 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -78,6 +78,7 @@
flag.StringVar(&cmdlineArgs.Bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
flag.StringVar(&cmdlineArgs.SymlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit")
flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
+ flag.StringVar(&cmdlineArgs.SoongVariables, "soong_variables", "soong.variables", "the file contains all build variables")
flag.StringVar(&cmdlineArgs.BazelForceEnabledModules, "bazel-force-enabled-modules", "", "additional modules to build with Bazel. Comma-delimited")
flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
flag.BoolVar(&cmdlineArgs.MultitreeBuild, "multitree-build", false, "this is a multitree build")
@@ -517,6 +518,8 @@
var finalOutputFile string
+ writeSymlink := false
+
// Run Soong for a specific activity, like bp2build, queryview
// or the actual Soong build for the build.ninja file.
switch configuration.BuildMode {
@@ -539,8 +542,13 @@
maybeQuit(err, "")
}
}
+ writeSymlink = true
} else {
finalOutputFile = runSoongOnlyBuild(ctx, extraNinjaDeps)
+
+ if configuration.BuildMode == android.AnalysisNoBazel {
+ writeSymlink = true
+ }
}
writeMetrics(configuration, ctx.EventHandler, metricsDir)
}
@@ -551,6 +559,24 @@
// are ninja inputs to the main output file, then ninja would superfluously
// rebuild this output file on the next build invocation.
touch(shared.JoinPath(topDir, finalOutputFile))
+
+ // TODO(b/277029044): Remove this function once build.<product>.ninja lands
+ if writeSymlink {
+ writeBuildNinjaSymlink(configuration, finalOutputFile)
+ }
+}
+
+// TODO(b/277029044): Remove this function once build.<product>.ninja lands
+func writeBuildNinjaSymlink(config android.Config, source string) {
+ targetPath := shared.JoinPath(topDir, config.SoongOutDir(), "build.ninja")
+ sourcePath := shared.JoinPath(topDir, source)
+
+ if targetPath == sourcePath {
+ return
+ }
+
+ os.Remove(targetPath)
+ os.Symlink(sourcePath, targetPath)
}
func writeUsedEnvironmentFile(configuration android.Config) {
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index afb3de3..6ead589 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -17,11 +17,11 @@
import (
"encoding/json"
"fmt"
- "sort"
"strconv"
- "strings"
"android/soong/android"
+
+ "github.com/google/blueprint/proptools"
)
// This comment describes the following:
@@ -310,8 +310,8 @@
// Nested class loader context shouldn't have conditional part (it is allowed only at the top level).
for ver, _ := range nestedClcMap {
if ver != AnySdkVersion {
- clcStr, _ := ComputeClassLoaderContext(nestedClcMap)
- return fmt.Errorf("nested class loader context shouldn't have conditional part: %s", clcStr)
+ clcPaths := ComputeClassLoaderContextDependencies(nestedClcMap)
+ return fmt.Errorf("nested class loader context shouldn't have conditional part: %+v", clcPaths)
}
}
subcontexts := nestedClcMap[AnySdkVersion]
@@ -418,6 +418,15 @@
return string(bytes)
}
+func (clcMap ClassLoaderContextMap) DumpForFlag() string {
+ jsonCLC := toJsonClassLoaderContext(clcMap)
+ bytes, err := json.Marshal(jsonCLC)
+ if err != nil {
+ panic(err)
+ }
+ return proptools.ShellEscapeIncludingSpaces(string(bytes))
+}
+
// excludeLibsFromCLCList excludes the libraries from the ClassLoaderContext in this list.
//
// This treats the supplied list as being immutable (as it may come from a dependency). So, it
@@ -544,67 +553,27 @@
return true, nil
}
-// Return the class loader context as a string, and a slice of build paths for all dependencies.
+// Returns a slice of build paths for all possible dependencies that the class loader context may
+// refer to.
// Perform a depth-first preorder traversal of the class loader context tree for each SDK version.
-// Return the resulting string and a slice of on-host build paths to all library dependencies.
-func ComputeClassLoaderContext(clcMap ClassLoaderContextMap) (clcStr string, paths android.Paths) {
- // CLC for different SDK versions should come in specific order that agrees with PackageManager.
- // Since PackageManager processes SDK versions in ascending order and prepends compatibility
- // libraries at the front, the required order is descending, except for AnySdkVersion that has
- // numerically the largest order, but must be the last one. Example of correct order: [30, 29,
- // 28, AnySdkVersion]. There are Soong tests to ensure that someone doesn't change this by
- // accident, but there is no way to guard against changes in the PackageManager, except for
- // grepping logcat on the first boot for absence of the following messages:
- //
- // `logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch`
- //
- versions := make([]int, 0, len(clcMap))
- for ver, _ := range clcMap {
- if ver != AnySdkVersion {
- versions = append(versions, ver)
- }
- }
- sort.Sort(sort.Reverse(sort.IntSlice(versions))) // descending order
- versions = append(versions, AnySdkVersion)
-
- for _, sdkVer := range versions {
- sdkVerStr := fmt.Sprintf("%d", sdkVer)
- if sdkVer == AnySdkVersion {
- sdkVerStr = "any" // a special keyword that means any SDK version
- }
- hostClc, targetClc, hostPaths := computeClassLoaderContextRec(clcMap[sdkVer])
- if hostPaths != nil {
- clcStr += fmt.Sprintf(" --host-context-for-sdk %s %s", sdkVerStr, hostClc)
- clcStr += fmt.Sprintf(" --target-context-for-sdk %s %s", sdkVerStr, targetClc)
- }
+func ComputeClassLoaderContextDependencies(clcMap ClassLoaderContextMap) android.Paths {
+ var paths android.Paths
+ for _, clcs := range clcMap {
+ hostPaths := ComputeClassLoaderContextDependenciesRec(clcs)
paths = append(paths, hostPaths...)
}
- return clcStr, android.FirstUniquePaths(paths)
+ return android.FirstUniquePaths(paths)
}
-// Helper function for ComputeClassLoaderContext() that handles recursion.
-func computeClassLoaderContextRec(clcs []*ClassLoaderContext) (string, string, android.Paths) {
+// Helper function for ComputeClassLoaderContextDependencies() that handles recursion.
+func ComputeClassLoaderContextDependenciesRec(clcs []*ClassLoaderContext) android.Paths {
var paths android.Paths
- var clcsHost, clcsTarget []string
-
for _, clc := range clcs {
- subClcHost, subClcTarget, subPaths := computeClassLoaderContextRec(clc.Subcontexts)
- if subPaths != nil {
- subClcHost = "{" + subClcHost + "}"
- subClcTarget = "{" + subClcTarget + "}"
- }
-
- clcsHost = append(clcsHost, "PCL["+clc.Host.String()+"]"+subClcHost)
- clcsTarget = append(clcsTarget, "PCL["+clc.Device+"]"+subClcTarget)
-
+ subPaths := ComputeClassLoaderContextDependenciesRec(clc.Subcontexts)
paths = append(paths, clc.Host)
paths = append(paths, subPaths...)
}
-
- clcHost := strings.Join(clcsHost, "#")
- clcTarget := strings.Join(clcsTarget, "#")
-
- return clcHost, clcTarget, paths
+ return paths
}
// Class loader contexts that come from Make via JSON dexpreopt.config. JSON CLC representation is
diff --git a/dexpreopt/class_loader_context_test.go b/dexpreopt/class_loader_context_test.go
index 8b3c013..39b4652 100644
--- a/dexpreopt/class_loader_context_test.go
+++ b/dexpreopt/class_loader_context_test.go
@@ -20,6 +20,7 @@
import (
"fmt"
"reflect"
+ "sort"
"strings"
"testing"
@@ -34,7 +35,7 @@
// │ └── android.hidl.base
// │
// └── any
- // ├── a
+ // ├── a' (a single quotation mark (') is there to test escaping)
// ├── b
// ├── c
// ├── d
@@ -53,7 +54,7 @@
m := make(ClassLoaderContextMap)
- m.AddContext(ctx, AnySdkVersion, "a", optional, buildPath(ctx, "a"), installPath(ctx, "a"), nil)
+ 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)
@@ -96,11 +97,10 @@
fixClassLoaderContext(m)
- var haveStr string
var havePaths android.Paths
var haveUsesLibsReq, haveUsesLibsOpt []string
if valid && validationError == nil {
- haveStr, havePaths = ComputeClassLoaderContext(m)
+ havePaths = ComputeClassLoaderContextDependencies(m)
haveUsesLibsReq, haveUsesLibsOpt = m.UsesLibs()
}
@@ -111,29 +111,6 @@
}
})
- // Test that class loader context structure is correct.
- t.Run("string", func(t *testing.T) {
- wantStr := " --host-context-for-sdk 29 " +
- "PCL[out/soong/" + AndroidHidlManager + ".jar]#" +
- "PCL[out/soong/" + AndroidHidlBase + ".jar]" +
- " --target-context-for-sdk 29 " +
- "PCL[/system/framework/" + AndroidHidlManager + ".jar]#" +
- "PCL[/system/framework/" + AndroidHidlBase + ".jar]" +
- " --host-context-for-sdk any " +
- "PCL[out/soong/a.jar]#PCL[out/soong/b.jar]#PCL[out/soong/c.jar]#PCL[out/soong/d.jar]" +
- "{PCL[out/soong/a2.jar]#PCL[out/soong/b2.jar]#PCL[out/soong/c2.jar]" +
- "{PCL[out/soong/a1.jar]#PCL[out/soong/b1.jar]}}#" +
- "PCL[out/soong/f.jar]#PCL[out/soong/a3.jar]#PCL[out/soong/b3.jar]" +
- " --target-context-for-sdk any " +
- "PCL[/system/a.jar]#PCL[/system/b.jar]#PCL[/system/c.jar]#PCL[/system/d.jar]" +
- "{PCL[/system/a2.jar]#PCL[/system/b2.jar]#PCL[/system/c2.jar]" +
- "{PCL[/system/a1.jar]#PCL[/system/b1.jar]}}#" +
- "PCL[/system/f.jar]#PCL[/system/a3.jar]#PCL[/system/b3.jar]"
- if wantStr != haveStr {
- t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
- }
- })
-
// Test that all expected build paths are gathered.
t.Run("paths", func(t *testing.T) {
wantPaths := []string{
@@ -143,14 +120,28 @@
"out/soong/a1.jar", "out/soong/b1.jar",
"out/soong/f.jar", "out/soong/a3.jar", "out/soong/b3.jar",
}
- if !reflect.DeepEqual(wantPaths, havePaths.Strings()) {
- t.Errorf("\nwant paths: %s\nhave paths: %s", wantPaths, havePaths)
- }
+ actual := havePaths.Strings()
+ // The order does not matter.
+ sort.Strings(wantPaths)
+ sort.Strings(actual)
+ android.AssertArrayString(t, "", wantPaths, actual)
+ })
+
+ // Test the JSON passed to construct_context.py.
+ t.Run("json", func(t *testing.T) {
+ // The tree structure within each SDK version should be kept exactly the same when serialized
+ // to JSON. The order matters because the Python script keeps the order within each SDK version
+ // as is.
+ // The JSON is passed to the Python script as a commandline flag, so quotation ('') and escaping
+ // must be performed.
+ android.AssertStringEquals(t, "", strings.TrimSpace(`
+'{"29":[{"Name":"android.hidl.manager-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.manager-V1.0-java.jar","Device":"/system/framework/android.hidl.manager-V1.0-java.jar","Subcontexts":[]},{"Name":"android.hidl.base-V1.0-java","Optional":false,"Host":"out/soong/android.hidl.base-V1.0-java.jar","Device":"/system/framework/android.hidl.base-V1.0-java.jar","Subcontexts":[]}],"30":[],"42":[],"any":[{"Name":"a'\''","Optional":false,"Host":"out/soong/a.jar","Device":"/system/a.jar","Subcontexts":[]},{"Name":"b","Optional":false,"Host":"out/soong/b.jar","Device":"/system/b.jar","Subcontexts":[]},{"Name":"c","Optional":false,"Host":"out/soong/c.jar","Device":"/system/c.jar","Subcontexts":[]},{"Name":"d","Optional":false,"Host":"out/soong/d.jar","Device":"/system/d.jar","Subcontexts":[{"Name":"a2","Optional":false,"Host":"out/soong/a2.jar","Device":"/system/a2.jar","Subcontexts":[]},{"Name":"b2","Optional":false,"Host":"out/soong/b2.jar","Device":"/system/b2.jar","Subcontexts":[]},{"Name":"c2","Optional":false,"Host":"out/soong/c2.jar","Device":"/system/c2.jar","Subcontexts":[{"Name":"a1","Optional":false,"Host":"out/soong/a1.jar","Device":"/system/a1.jar","Subcontexts":[]},{"Name":"b1","Optional":false,"Host":"out/soong/b1.jar","Device":"/system/b1.jar","Subcontexts":[]}]}]},{"Name":"f","Optional":false,"Host":"out/soong/f.jar","Device":"/system/f.jar","Subcontexts":[]},{"Name":"a3","Optional":false,"Host":"out/soong/a3.jar","Device":"/system/a3.jar","Subcontexts":[]},{"Name":"b3","Optional":false,"Host":"out/soong/b3.jar","Device":"/system/b3.jar","Subcontexts":[]}]}'
+`), m.DumpForFlag())
})
// Test for libraries that are added by the manifest_fixer.
t.Run("uses libs", func(t *testing.T) {
- wantUsesLibsReq := []string{"a", "b", "c", "d", "f", "a3", "b3"}
+ wantUsesLibsReq := []string{"a'", "b", "c", "d", "f", "a3", "b3"}
wantUsesLibsOpt := []string{}
if !reflect.DeepEqual(wantUsesLibsReq, haveUsesLibsReq) {
t.Errorf("\nwant required uses libs: %s\nhave required uses libs: %s", wantUsesLibsReq, haveUsesLibsReq)
@@ -236,49 +227,6 @@
checkError(t, err, "nested class loader context shouldn't have conditional part")
}
-// Test for SDK version order in conditional CLC: no matter in what order the libraries are added,
-// they end up in the order that agrees with PackageManager.
-func TestCLCSdkVersionOrder(t *testing.T) {
- ctx := testContext()
- optional := false
- 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)
-
- valid, validationError := validateClassLoaderContext(m)
-
- fixClassLoaderContext(m)
-
- var haveStr string
- if valid && validationError == nil {
- haveStr, _ = ComputeClassLoaderContext(m)
- }
-
- // Test that validation is successful (all paths are known).
- t.Run("validate", func(t *testing.T) {
- if !(valid && validationError == nil) {
- t.Errorf("invalid class loader context")
- }
- })
-
- // Test that class loader context structure is correct.
- t.Run("string", func(t *testing.T) {
- wantStr := " --host-context-for-sdk 30 PCL[out/soong/c.jar]" +
- " --target-context-for-sdk 30 PCL[/system/c.jar]" +
- " --host-context-for-sdk 29 PCL[out/soong/b.jar]" +
- " --target-context-for-sdk 29 PCL[/system/b.jar]" +
- " --host-context-for-sdk 28 PCL[out/soong/a.jar]" +
- " --target-context-for-sdk 28 PCL[/system/a.jar]" +
- " --host-context-for-sdk any PCL[out/soong/d.jar]" +
- " --target-context-for-sdk any PCL[/system/d.jar]"
- if wantStr != haveStr {
- t.Errorf("\nwant class loader context: %s\nhave class loader context: %s", wantStr, haveStr)
- }
- })
-}
-
func TestCLCMExcludeLibs(t *testing.T) {
ctx := testContext()
const optional = false
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 2b38793..20737e3 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -52,7 +52,8 @@
// GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a
// ModuleConfig. The produced files and their install locations will be available through rule.Installs().
func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
- global *GlobalConfig, module *ModuleConfig) (rule *android.RuleBuilder, err error) {
+ global *GlobalConfig, module *ModuleConfig, productPackages android.Path) (
+ rule *android.RuleBuilder, err error) {
defer func() {
if r := recover(); r != nil {
@@ -92,7 +93,8 @@
generateDM := shouldGenerateDM(module, global)
for archIdx, _ := range module.Archs {
- dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
+ dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage,
+ generateDM, productPackages)
}
}
}
@@ -232,9 +234,9 @@
pathtools.ReplaceExtension(filepath.Base(path), "odex"))
}
-func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
- module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
- appImage bool, generateDM bool) {
+func dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig,
+ global *GlobalConfig, module *ModuleConfig, rule *android.RuleBuilder, archIdx int,
+ profile android.WritablePath, appImage bool, generateDM bool, productPackages android.Path) {
arch := module.Archs[archIdx]
@@ -351,11 +353,13 @@
}
// Generate command that saves host and target class loader context in shell variables.
- clc, paths := ComputeClassLoaderContext(module.ClassLoaderContexts)
+ paths := ComputeClassLoaderContextDependencies(module.ClassLoaderContexts)
rule.Command().
Text(`eval "$(`).Tool(globalSoong.ConstructContext).
Text(` --target-sdk-version ${target_sdk_version}`).
- Text(clc).Implicits(paths).
+ FlagWithArg("--context-json=", module.ClassLoaderContexts.DumpForFlag()).
+ FlagWithInput("--product-packages=", productPackages).
+ Implicits(paths).
Text(`)"`)
}
diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
index ba05d94..8033b48 100644
--- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
+++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go
@@ -42,7 +42,8 @@
// The flag is useful when running dex2oat on system image and vendor image which are built separately.
usesTargetFiles = flag.Bool("uses_target_files", false, "whether or not dexpreopt is running on target_files")
// basePath indicates the path where target_files.zip is extracted.
- basePath = flag.String("base_path", ".", "base path where images and tools are extracted")
+ basePath = flag.String("base_path", ".", "base path where images and tools are extracted")
+ productPackagesPath = flag.String("product_packages", "", "path to product_packages.txt")
)
type builderContext struct {
@@ -87,6 +88,10 @@
usage("--module configuration file is required")
}
+ if *productPackagesPath == "" {
+ usage("--product_packages configuration file is required")
+ }
+
// NOTE: duplicating --out_dir here is incorrect (one should be the another
// plus "/soong" but doing so apparently breaks dexpreopt
ctx := &builderContext{android.NullConfig(*outDir, *outDir)}
@@ -159,11 +164,12 @@
moduleConfig.DexPreoptImageLocationsOnHost[i] = *basePath + location
}
}
- writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath)
+ writeScripts(ctx, globalSoongConfig, globalConfig, moduleConfig, *dexpreoptScriptPath, *productPackagesPath)
}
func writeScripts(ctx android.BuilderContext, globalSoong *dexpreopt.GlobalSoongConfig,
- global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string) {
+ global *dexpreopt.GlobalConfig, module *dexpreopt.ModuleConfig, dexpreoptScriptPath string,
+ productPackagesPath string) {
write := func(rule *android.RuleBuilder, file string) {
script := &bytes.Buffer{}
script.WriteString(scriptHeader)
@@ -199,7 +205,8 @@
panic(err)
}
}
- dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
+ ctx, globalSoong, global, module, android.PathForTesting(productPackagesPath))
if err != nil {
panic(err)
}
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 429b5ff..2b19c9d 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -100,8 +100,9 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testSystemModuleConfig(ctx, "test")
+ productPackages := android.PathForTesting("product_packages.txt")
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -124,6 +125,7 @@
systemModule := testSystemModuleConfig(ctx, "Stest")
systemProductModule := testSystemProductModuleConfig(ctx, "SPtest")
productModule := testProductModuleConfig(ctx, "Ptest")
+ productPackages := android.PathForTesting("product_packages.txt")
global.HasSystemOther = true
@@ -157,7 +159,7 @@
for _, test := range tests {
global.PatternsOnSystemOther = test.patterns
for _, mt := range test.moduleTests {
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -182,11 +184,12 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
+ productPackages := android.PathForTesting("product_packages.txt")
global.ApexSystemServerJars = android.CreateTestConfiguredJarList(
[]string{"com.android.apex1:service-A"})
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -205,11 +208,12 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testPlatformSystemServerModuleConfig(ctx, "service-A")
+ productPackages := android.PathForTesting("product_packages.txt")
global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
[]string{"platform:service-A"})
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -228,11 +232,12 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testSystemExtSystemServerModuleConfig(ctx, "service-A")
+ productPackages := android.PathForTesting("product_packages.txt")
global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
[]string{"system_ext:service-A"})
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -251,11 +256,12 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
+ productPackages := android.PathForTesting("product_packages.txt")
global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList(
[]string{"com.android.apex1:service-A"})
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
@@ -274,10 +280,11 @@
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testSystemModuleConfig(ctx, "test")
+ productPackages := android.PathForTesting("product_packages.txt")
module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile"))
- rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages)
if err != nil {
t.Fatal(err)
}
diff --git a/java/app.go b/java/app.go
index d0bde6f..561ce1d 100755
--- a/java/app.go
+++ b/java/app.go
@@ -613,7 +613,6 @@
}
}
-
return mainCertificate, certificates
}
@@ -795,17 +794,17 @@
// Install the app package.
shouldInstallAppPackage := (Bool(a.Module.properties.Installable) || ctx.Host()) && apexInfo.IsForPlatform() && !a.appProperties.PreventInstall
if shouldInstallAppPackage {
+ if a.privAppAllowlist.Valid() {
+ installPath := android.PathForModuleInstall(ctx, "etc", "permissions")
+ ctx.InstallFile(installPath, a.privAppAllowlist.Path().Base(), a.privAppAllowlist.Path())
+ }
+
var extraInstalledPaths android.Paths
for _, extra := range a.extraOutputFiles {
installed := ctx.InstallFile(a.installDir, extra.Base(), extra)
extraInstalledPaths = append(extraInstalledPaths, installed)
}
ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
-
- if a.privAppAllowlist.Valid() {
- installPath := android.PathForModuleInstall(ctx, "etc", "permissions")
- ctx.InstallFile(installPath, a.privAppAllowlist.Path().Base(), a.privAppAllowlist.Path())
- }
}
a.buildAppDependencyInfo(ctx)
diff --git a/java/app_test.go b/java/app_test.go
index 4b78c48..7f9f0ed 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2693,52 +2693,11 @@
`--optional-uses-library baz `
android.AssertStringDoesContain(t, "verify apk cmd args", verifyApkCmd, verifyApkArgs)
- // Test that all present libraries are preopted, including implicit SDK dependencies, possibly stubs
+ // Test that necessary args are passed for constructing CLC in Ninja phase.
cmd := app.Rule("dexpreopt").RuleParams.Command
- w := `--target-context-for-sdk any ` +
- `PCL[/system/framework/qux.jar]#` +
- `PCL[/system/framework/quuz.jar]#` +
- `PCL[/system/framework/foo.jar]#` +
- `PCL[/system/framework/non-sdk-lib.jar]#` +
- `PCL[/system/framework/bar.jar]#` +
- `PCL[/system/framework/runtime-library.jar]#` +
- `PCL[/system/framework/runtime-required-x.jar]#` +
- `PCL[/system/framework/runtime-optional-x.jar]#` +
- `PCL[/system/framework/runtime-required-y.jar]#` +
- `PCL[/system/framework/runtime-optional-y.jar] `
- android.AssertStringDoesContain(t, "dexpreopt app cmd args", cmd, w)
-
- // Test conditional context for target SDK version 28.
- android.AssertStringDoesContain(t, "dexpreopt app cmd 28", cmd,
- `--target-context-for-sdk 28`+
- ` PCL[/system/framework/org.apache.http.legacy.jar] `)
-
- // Test conditional context for target SDK version 29.
- android.AssertStringDoesContain(t, "dexpreopt app cmd 29", cmd,
- `--target-context-for-sdk 29`+
- ` PCL[/system/framework/android.hidl.manager-V1.0-java.jar]`+
- `#PCL[/system/framework/android.hidl.base-V1.0-java.jar] `)
-
- // Test conditional context for target SDK version 30.
- // "android.test.mock" is absent because "android.test.runner" is not used.
- android.AssertStringDoesContain(t, "dexpreopt app cmd 30", cmd,
- `--target-context-for-sdk 30`+
- ` PCL[/system/framework/android.test.base.jar] `)
-
- cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
- android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd", cmd,
- `--target-context-for-sdk any`+
- ` PCL[/system/framework/foo.jar]`+
- `#PCL[/system/framework/non-sdk-lib.jar]`+
- `#PCL[/system/framework/android.test.runner.jar]`+
- `#PCL[/system/framework/bar.jar] `)
-
- // Test conditional context for target SDK version 30.
- // "android.test.mock" is present because "android.test.runner" is used.
- android.AssertStringDoesContain(t, "dexpreopt prebuilt cmd 30", cmd,
- `--target-context-for-sdk 30`+
- ` PCL[/system/framework/android.test.base.jar]`+
- `#PCL[/system/framework/android.test.mock.jar] `)
+ android.AssertStringDoesContain(t, "dexpreopt app cmd context", cmd, "--context-json=")
+ android.AssertStringDoesContain(t, "dexpreopt app cmd product_packages", cmd,
+ "--product-packages=out/soong/target/product/test_device/product_packages.txt")
}
func TestDexpreoptBcp(t *testing.T) {
@@ -3589,3 +3548,82 @@
app.Output("out/soong/target/product/test_device/system/etc/permissions/privapp_allowlist_com.android.foo.xml")
overrideApp.Output("out/soong/target/product/test_device/system/etc/permissions/privapp_allowlist_com.google.android.foo.xml")
}
+
+func TestPrivappAllowlistAndroidMk(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ android.PrepareForTestWithAndroidMk,
+ ).RunTestWithBp(
+ t,
+ `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ privapp_allowlist: "privapp_allowlist_com.android.foo.xml",
+ privileged: true,
+ sdk_version: "current",
+ }
+ override_android_app {
+ name: "bar",
+ base: "foo",
+ package_name: "com.google.android.foo",
+ }
+ `,
+ )
+ baseApp := result.ModuleForTests("foo", "android_common")
+ overrideApp := result.ModuleForTests("foo", "android_common_bar")
+
+ baseAndroidApp := baseApp.Module().(*AndroidApp)
+ baseEntries := android.AndroidMkEntriesForTest(t, result.TestContext, baseAndroidApp)[0]
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALLED_MODULE; expected to find foo.apk",
+ baseEntries.EntryMap["LOCAL_SOONG_INSTALLED_MODULE"][0],
+ "\\S+foo.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include foo.apk",
+ baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+foo.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include app",
+ baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+foo.apk:\\S+/target/product/test_device/system/priv-app/foo/foo.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include privapp_allowlist",
+ baseEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "privapp_allowlist_com.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/privapp_allowlist_com.android.foo.xml",
+ )
+
+ overrideAndroidApp := overrideApp.Module().(*AndroidApp)
+ overrideEntries := android.AndroidMkEntriesForTest(t, result.TestContext, overrideAndroidApp)[0]
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALLED_MODULE; expected to find bar.apk",
+ overrideEntries.EntryMap["LOCAL_SOONG_INSTALLED_MODULE"][0],
+ "\\S+bar.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include bar.apk",
+ overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+bar.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include app",
+ overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+bar.apk:\\S+/target/product/test_device/system/priv-app/bar/bar.apk",
+ )
+ android.AssertStringMatches(
+ t,
+ "androidmk has incorrect LOCAL_SOONG_INSTALL_PAIRS; expected to it to include privapp_allowlist",
+ overrideEntries.EntryMap["LOCAL_SOONG_INSTALL_PAIRS"][0],
+ "\\S+soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml:\\S+/target/product/test_device/system/etc/permissions/privapp_allowlist_com.google.android.foo.xml",
+ )
+}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index a96b312..e588c9a 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -390,7 +390,11 @@
globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
- dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
+ // "product_packages.txt" is generated by `build/make/core/Makefile`.
+ productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt")
+
+ dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
+ ctx, globalSoong, global, dexpreoptConfig, productPackages)
if err != nil {
ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
return
diff --git a/java/fuzz.go b/java/fuzz.go
index 5c5f769..5dfaacf 100644
--- a/java/fuzz.go
+++ b/java/fuzz.go
@@ -177,7 +177,11 @@
files = s.PackageArtifacts(ctx, module, javaFuzzModule.fuzzPackagedModule, archDir, builder)
// Add .jar
- files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.implementationJarFile})
+ if !javaFuzzModule.Host() {
+ files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.implementationJarFile, DestinationPathPrefix: "classes"})
+ }
+
+ files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.outputFile})
// Add jni .so files
for _, fPath := range javaFuzzModule.jniFilePaths {
diff --git a/java/java.go b/java/java.go
index a23526a..aa9f936 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1813,7 +1813,7 @@
case javaApiContributionTag:
provider := ctx.OtherModuleProvider(dep, JavaApiImportProvider).(JavaApiImportInfo)
providerApiFile := provider.ApiFile
- if providerApiFile == nil {
+ if providerApiFile == nil && !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("Error: %s has an empty api file.", dep.Name())
}
srcFiles = append(srcFiles, android.PathForSource(ctx, providerApiFile.String()))
@@ -1835,7 +1835,7 @@
srcFiles = append(srcFiles, android.PathForModuleSrc(ctx, api))
}
- if srcFiles == nil {
+ if srcFiles == nil && !ctx.Config().AllowMissingDependencies() {
ctx.ModuleErrorf("Error: %s has an empty api file.", ctx.ModuleName())
}
@@ -2704,6 +2704,15 @@
Resource_strip_prefix *string
}
+func (m *Library) javaResourcesGetSingleFilegroupStripPrefix(ctx android.TopDownMutatorContext) (string, bool) {
+ if otherM, ok := ctx.ModuleFromName(m.properties.Java_resources[0]); ok && len(m.properties.Java_resources) == 1 {
+ if fg, isFilegroup := otherM.(android.FileGroupPath); isFilegroup {
+ return filepath.Join(ctx.OtherModuleDir(otherM), fg.GetPath(ctx)), true
+ }
+ }
+ return "", false
+}
+
func (m *Library) convertJavaResourcesAttributes(ctx android.TopDownMutatorContext) *javaResourcesAttributes {
var resources bazel.LabelList
var resourceStripPrefix *string
@@ -2713,8 +2722,12 @@
}
if m.properties.Java_resources != nil {
+ if prefix, ok := m.javaResourcesGetSingleFilegroupStripPrefix(ctx); ok {
+ resourceStripPrefix = proptools.StringPtr(prefix)
+ } else {
+ resourceStripPrefix = proptools.StringPtr(ctx.ModuleDir())
+ }
resources.Append(android.BazelLabelForModuleSrc(ctx, m.properties.Java_resources))
- resourceStripPrefix = proptools.StringPtr(ctx.ModuleDir())
}
//TODO(b/179889880) handle case where glob includes files outside package
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 8225df6..c0ae0c0 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -870,7 +870,7 @@
}
// Safeguard against $(call inherit-product,$(PRODUCT_PATH))
- const maxMatchingFiles = 150
+ const maxMatchingFiles = 155 // temporarily increased to 155 for b/284854738
if len(matchingPaths) > maxMatchingFiles {
return []starlarkNode{ctx.newBadNode(v, "there are >%d files matching the pattern, please rewrite it", maxMatchingFiles)}
}
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index 865665e..7fa9f5c 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -46,18 +46,16 @@
// Check that compiler flags are set appropriately .
fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc")
- if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
- !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
+ if !strings.Contains(fuzz_libtest.Args["rustcFlags"], "-C passes='sancov-module'") ||
!strings.Contains(fuzz_libtest.Args["rustcFlags"], "--cfg fuzzing") {
- t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing, hwaddress sanitizer).")
+ t.Errorf("rust_fuzz module does not contain the expected flags (sancov-module, cfg fuzzing).")
}
// Check that dependencies have 'fuzzer' variants produced for them as well.
libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib")
- if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-Z sanitizer=hwaddress") ||
- !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
+ if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") ||
!strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") {
- t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing, hwaddress sanitizer).")
+ t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing).")
}
}
diff --git a/rust/sanitize.go b/rust/sanitize.go
index c68137e..83cf055 100644
--- a/rust/sanitize.go
+++ b/rust/sanitize.go
@@ -226,11 +226,6 @@
}
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
flags.RustFlags = append(flags.RustFlags, fuzzerFlags...)
- if ctx.Arch().ArchType == android.Arm64 && ctx.Os().Bionic() {
- flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
- } else {
- flags.RustFlags = append(flags.RustFlags, asanFlags...)
- }
} else if Bool(sanitize.Properties.Sanitize.Hwaddress) {
flags.RustFlags = append(flags.RustFlags, hwasanFlags...)
} else if Bool(sanitize.Properties.Sanitize.Address) {
@@ -424,14 +419,6 @@
return true
}
- // TODO(b/178365482): Rust/CC interop doesn't work just yet; don't sanitize rust_ffi modules until
- // linkage issues are resolved.
- if lib, ok := mod.compiler.(libraryInterface); ok {
- if lib.shared() || lib.static() {
- return true
- }
- }
-
return mod.sanitize.isSanitizerExplicitlyDisabled(t)
}
diff --git a/scripts/construct_context.py b/scripts/construct_context.py
index 3f601c3..fc3a89e 100755
--- a/scripts/construct_context.py
+++ b/scripts/construct_context.py
@@ -19,6 +19,7 @@
from __future__ import print_function
import argparse
+import json
import sys
from manifest import compare_version_gt
@@ -33,20 +34,14 @@
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')
+ '--context-json',
+ default='',
+ dest='context_json',
+ )
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'
+ '--product-packages',
+ default='',
+ dest='product_packages_file',
)
return parser.parse_args(args)
@@ -55,28 +50,69 @@
# 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_sep = '#'
-def construct_contexts(args):
- host_context = construct_context(args.host_contexts, args.sdk)
- target_context = construct_context(args.target_contexts, args.sdk)
- context_sep = '#'
+def encode_class_loader(context, product_packages):
+ host_sub_contexts, target_sub_contexts = encode_class_loaders(
+ context['Subcontexts'], product_packages)
+
+ return ('PCL[%s]%s' % (context['Host'], host_sub_contexts),
+ 'PCL[%s]%s' % (context['Device'], target_sub_contexts))
+
+
+def encode_class_loaders(contexts, product_packages):
+ host_contexts = []
+ target_contexts = []
+
+ for context in contexts:
+ if not context['Optional'] or context['Name'] in product_packages:
+ host_context, target_context = encode_class_loader(
+ context, product_packages)
+ host_contexts.append(host_context)
+ target_contexts.append(target_context)
+
+ if host_contexts:
+ return ('{%s}' % context_sep.join(host_contexts),
+ '{%s}' % context_sep.join(target_contexts))
+ else:
+ return '', ''
+
+
+def construct_context_args(target_sdk, context_json, product_packages):
+ all_contexts = []
+
+ # CLC for different SDK versions should come in specific order that agrees
+ # with PackageManager. Since PackageManager processes SDK versions in
+ # ascending order and prepends compatibility libraries at the front, the
+ # required order is descending, except for any_sdk that has numerically
+ # the largest order, but must be the last one. Example of correct order:
+ # [30, 29, 28, any_sdk]. There are Python tests to ensure that someone
+ # doesn't change this by accident, but there is no way to guard against
+ # changes in the PackageManager, except for grepping logcat on the first
+ # boot for absence of the following messages:
+ #
+ # `logcat | grep -E 'ClassLoaderContext [a-z ]+ mismatch`
+
+ for sdk, contexts in sorted(
+ ((sdk, contexts)
+ for sdk, contexts in context_json.items()
+ if sdk != any_sdk and compare_version_gt(sdk, target_sdk)),
+ key=lambda item: int(item[0]), reverse=True):
+ all_contexts += contexts
+
+ if any_sdk in context_json:
+ all_contexts += context_json[any_sdk]
+
+ host_contexts, target_contexts = encode_class_loaders(
+ all_contexts, product_packages)
+
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))
+ 'class_loader_context_arg=--class-loader-context=PCL[]%s ; ' %
+ host_contexts +
+ 'stored_class_loader_context_arg='
+ '--stored-class-loader-context=PCL[]%s'
+ % target_contexts)
def main():
@@ -85,12 +121,12 @@
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))
+ context_json = json.loads(args.context_json)
+ with open(args.product_packages_file, 'r') as f:
+ product_packages = set(line.strip() for line in f if line.strip())
+
+ print(construct_context_args(args.sdk, context_json, product_packages))
# pylint: disable=broad-except
except Exception as err:
diff --git a/scripts/construct_context_test.py b/scripts/construct_context_test.py
index 2ff5ac5..34a0e16 100755
--- a/scripts/construct_context_test.py
+++ b/scripts/construct_context_test.py
@@ -24,62 +24,249 @@
sys.dont_write_bytecode = True
-def construct_contexts(arglist):
- args = cc.parse_args(arglist)
- return cc.construct_contexts(args)
+CONTEXT_JSON = {
+ '28': [
+ {
+ 'Name': 'z',
+ 'Optional': False,
+ 'Host': 'out/zdir/z.jar',
+ 'Device': '/system/z.jar',
+ 'Subcontexts': [],
+ },
+ ],
+ '29': [
+ {
+ 'Name': 'x',
+ 'Optional': False,
+ 'Host': 'out/xdir/x.jar',
+ 'Device': '/system/x.jar',
+ 'Subcontexts': [],
+ },
+ {
+ 'Name': 'y',
+ 'Optional': False,
+ 'Host': 'out/ydir/y.jar',
+ 'Device': '/product/y.jar',
+ 'Subcontexts': [],
+ },
+ ],
+ 'any': [
+ {
+ 'Name': 'a',
+ 'Optional': False,
+ 'Host': 'out/adir/a.jar',
+ 'Device': '/system/a.jar',
+ 'Subcontexts': [
+ { # Not installed optional, being the only child.
+ 'Name': 'a1',
+ 'Optional': True,
+ 'Host': 'out/a1dir/a1.jar',
+ 'Device': '/product/a1.jar',
+ 'Subcontexts': [],
+ },
+ ],
+ },
+ {
+ 'Name': 'b',
+ 'Optional': True,
+ 'Host': 'out/bdir/b.jar',
+ 'Device': '/product/b.jar',
+ 'Subcontexts': [
+ { # Not installed but required.
+ 'Name': 'b1',
+ 'Optional': False,
+ 'Host': 'out/b1dir/b1.jar',
+ 'Device': '/product/b1.jar',
+ 'Subcontexts': [],
+ },
+ { # Installed optional.
+ 'Name': 'b2',
+ 'Optional': True,
+ 'Host': 'out/b2dir/b2.jar',
+ 'Device': '/product/b2.jar',
+ 'Subcontexts': [],
+ },
+ { # Not installed optional.
+ 'Name': 'b3',
+ 'Optional': True,
+ 'Host': 'out/b3dir/b3.jar',
+ 'Device': '/product/b3.jar',
+ 'Subcontexts': [],
+ },
+ { # Installed optional with one more level of nested deps.
+ 'Name': 'b4',
+ 'Optional': True,
+ 'Host': 'out/b4dir/b4.jar',
+ 'Device': '/product/b4.jar',
+ 'Subcontexts': [
+ {
+ 'Name': 'b41',
+ 'Optional': True,
+ 'Host': 'out/b41dir/b41.jar',
+ 'Device': '/product/b41.jar',
+ 'Subcontexts': [],
+ },
+ {
+ 'Name': 'b42',
+ 'Optional': True,
+ 'Host': 'out/b42dir/b42.jar',
+ 'Device': '/product/b42.jar',
+ 'Subcontexts': [],
+ },
+ ],
+ },
+ ],
+ },
+ { # Not installed optional, at the top-level.
+ 'Name': 'c',
+ 'Optional': True,
+ 'Host': 'out/cdir/c.jar',
+ 'Device': '/product/c.jar',
+ 'Subcontexts': [],
+ },
+ ],
+}
-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]',
-]
+PRODUCT_PACKAGES = ['a', 'b', 'b2', 'b4', 'b41', 'b42', 'x', 'y', 'z']
-#pylint: disable=line-too-long
+
+def construct_context_args(target_sdk):
+ return cc.construct_context_args(target_sdk, CONTEXT_JSON, PRODUCT_PACKAGES)
+
+
class ConstructContextTest(unittest.TestCase):
+ def test_construct_context_27(self):
+ actual = construct_context_args('27')
+ # The order matters.
+ expected = (
+ 'class_loader_context_arg='
+ '--class-loader-context=PCL[]{'
+ 'PCL[out/xdir/x.jar]#'
+ 'PCL[out/ydir/y.jar]#'
+ 'PCL[out/zdir/z.jar]#'
+ 'PCL[out/adir/a.jar]#'
+ 'PCL[out/bdir/b.jar]{'
+ 'PCL[out/b1dir/b1.jar]#'
+ 'PCL[out/b2dir/b2.jar]#'
+ 'PCL[out/b4dir/b4.jar]{'
+ 'PCL[out/b41dir/b41.jar]#'
+ 'PCL[out/b42dir/b42.jar]'
+ '}'
+ '}'
+ '}'
+ ' ; '
+ 'stored_class_loader_context_arg='
+ '--stored-class-loader-context=PCL[]{'
+ 'PCL[/system/x.jar]#'
+ 'PCL[/product/y.jar]#'
+ 'PCL[/system/z.jar]#'
+ 'PCL[/system/a.jar]#'
+ 'PCL[/product/b.jar]{'
+ 'PCL[/product/b1.jar]#'
+ 'PCL[/product/b2.jar]#'
+ 'PCL[/product/b4.jar]{'
+ 'PCL[/product/b41.jar]#'
+ 'PCL[/product/b42.jar]'
+ '}'
+ '}'
+ '}')
+ self.assertEqual(actual, expected)
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]}'
+ actual = construct_context_args('28')
+ expected = (
+ '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]{'
+ 'PCL[out/b1dir/b1.jar]#'
+ 'PCL[out/b2dir/b2.jar]#'
+ 'PCL[out/b4dir/b4.jar]{'
+ 'PCL[out/b41dir/b41.jar]#'
+ 'PCL[out/b42dir/b42.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)
+ '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]{'
+ 'PCL[/product/b1.jar]#'
+ 'PCL[/product/b2.jar]#'
+ 'PCL[/product/b4.jar]{'
+ 'PCL[/product/b41.jar]#'
+ 'PCL[/product/b42.jar]'
+ '}'
+ '}'
+ '}')
+ self.assertEqual(actual, expected)
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]}'
+ actual = construct_context_args('29')
+ expected = (
+ 'class_loader_context_arg='
+ '--class-loader-context=PCL[]{'
+ 'PCL[out/adir/a.jar]#'
+ 'PCL[out/bdir/b.jar]{'
+ 'PCL[out/b1dir/b1.jar]#'
+ 'PCL[out/b2dir/b2.jar]#'
+ 'PCL[out/b4dir/b4.jar]{'
+ 'PCL[out/b41dir/b41.jar]#'
+ 'PCL[out/b42dir/b42.jar]'
+ '}'
+ '}'
+ '}'
' ; '
- 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]#PCL[/product/b.jar]}')
- self.assertEqual(result, expect)
+ 'stored_class_loader_context_arg='
+ '--stored-class-loader-context=PCL[]{'
+ 'PCL[/system/a.jar]#'
+ 'PCL[/product/b.jar]{'
+ 'PCL[/product/b1.jar]#'
+ 'PCL[/product/b2.jar]#'
+ 'PCL[/product/b4.jar]{'
+ 'PCL[/product/b41.jar]#'
+ 'PCL[/product/b42.jar]'
+ '}'
+ '}'
+ '}')
+ self.assertEqual(actual, expected)
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]}'
+ actual = construct_context_args('S')
+ expected = (
+ 'class_loader_context_arg='
+ '--class-loader-context=PCL[]{'
+ 'PCL[out/adir/a.jar]#'
+ 'PCL[out/bdir/b.jar]{'
+ 'PCL[out/b1dir/b1.jar]#'
+ 'PCL[out/b2dir/b2.jar]#'
+ 'PCL[out/b4dir/b4.jar]{'
+ 'PCL[out/b41dir/b41.jar]#'
+ 'PCL[out/b42dir/b42.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
+ 'stored_class_loader_context_arg='
+ '--stored-class-loader-context=PCL[]{'
+ 'PCL[/system/a.jar]#'
+ 'PCL[/product/b.jar]{'
+ 'PCL[/product/b1.jar]#'
+ 'PCL[/product/b2.jar]#'
+ 'PCL[/product/b4.jar]{'
+ 'PCL[/product/b41.jar]#'
+ 'PCL[/product/b42.jar]'
+ '}'
+ '}'
+ '}')
+ self.assertEqual(actual, expected)
+
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index 2f154cd..94fe51d 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -90,10 +90,12 @@
-I /system/lib64/android.hardware.security.sharedsecret-V1-ndk.so \
-I /system/lib64/android.security.compat-ndk.so \
-I /system/lib64/libkeymaster4_1support.so \
+ -I /system/lib64/libkeymaster4support.so \
-I /system/lib64/libkeymint.so \
-I /system/lib64/libkeystore2_aaid.so \
-I /system/lib64/libkeystore2_apc_compat.so \
-I /system/lib64/libkeystore2_crypto.so \
+ -I /system/lib64/libkeystore-attestation-application-id.so \
-I /system/lib64/libkm_compat_service.so \
-I /system/lib64/libkm_compat.so \
-I /system/lib64/vndk-29 \
diff --git a/ui/build/config.go b/ui/build/config.go
index 45735ad..bfbf85d 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -1141,6 +1141,13 @@
panic("TARGET_PRODUCT is not defined")
}
+func (c *configImpl) TargetProductOrErr() (string, error) {
+ if v, ok := c.environ.Get("TARGET_PRODUCT"); ok {
+ return v, nil
+ }
+ return "", fmt.Errorf("TARGET_PRODUCT is not defined")
+}
+
func (c *configImpl) TargetDevice() string {
return c.targetDevice
}
@@ -1398,7 +1405,7 @@
if googleProdCredsExistCache {
return googleProdCredsExistCache
}
- if _, err := exec.Command("/usr/bin/prodcertstatus", "--simple_output", "--nocheck_loas").Output(); err != nil {
+ if _, err := exec.Command("/usr/bin/gcertstatus").Output(); err != nil {
return false
}
googleProdCredsExistCache = true
@@ -1466,11 +1473,21 @@
}
func (c *configImpl) SoongVarsFile() string {
- return filepath.Join(c.SoongOutDir(), "soong.variables")
+ targetProduct, err := c.TargetProductOrErr()
+ if err != nil {
+ return filepath.Join(c.SoongOutDir(), "soong.variables")
+ } else {
+ return filepath.Join(c.SoongOutDir(), "soong."+targetProduct+".variables")
+ }
}
func (c *configImpl) SoongNinjaFile() string {
- return filepath.Join(c.SoongOutDir(), "build.ninja")
+ targetProduct, err := c.TargetProductOrErr()
+ if err != nil {
+ return filepath.Join(c.SoongOutDir(), "build.ninja")
+ } else {
+ return filepath.Join(c.SoongOutDir(), "build."+targetProduct+".ninja")
+ }
}
func (c *configImpl) CombinedNinjaFile() string {
diff --git a/ui/build/soong.go b/ui/build/soong.go
index 18bf3b9..6de8d6f 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -235,7 +235,7 @@
} else if !exists {
// The tree is out of date for the current epoch, delete files used by bootstrap
// and force the primary builder to rerun.
- os.Remove(filepath.Join(config.SoongOutDir(), "build.ninja"))
+ os.Remove(config.SoongNinjaFile())
for _, globFile := range bootstrapGlobFileList(config) {
os.Remove(globFile)
}
@@ -263,7 +263,9 @@
// Clean up some files for incremental builds across incompatible changes.
bootstrapEpochCleanup(ctx, config)
- mainSoongBuildExtraArgs := []string{"-o", config.SoongNinjaFile()}
+ baseArgs := []string{"--soong_variables", config.SoongVarsFile()}
+
+ mainSoongBuildExtraArgs := append(baseArgs, "-o", config.SoongNinjaFile())
if config.EmptyNinjaFile() {
mainSoongBuildExtraArgs = append(mainSoongBuildExtraArgs, "--empty-ninja-file")
}
@@ -306,49 +308,59 @@
specificArgs: mainSoongBuildExtraArgs,
},
{
- name: bp2buildFilesTag,
- description: fmt.Sprintf("converting Android.bp files to BUILD files at %s/bp2build", config.SoongOutDir()),
- config: config,
- output: config.Bp2BuildFilesMarkerFile(),
- specificArgs: []string{"--bp2build_marker", config.Bp2BuildFilesMarkerFile()},
+ name: bp2buildFilesTag,
+ description: fmt.Sprintf("converting Android.bp files to BUILD files at %s/bp2build", config.SoongOutDir()),
+ config: config,
+ output: config.Bp2BuildFilesMarkerFile(),
+ specificArgs: append(baseArgs,
+ "--bp2build_marker", config.Bp2BuildFilesMarkerFile(),
+ ),
},
{
- name: bp2buildWorkspaceTag,
- description: "Creating Bazel symlink forest",
- config: config,
- output: config.Bp2BuildWorkspaceMarkerFile(),
- specificArgs: []string{"--symlink_forest_marker", config.Bp2BuildWorkspaceMarkerFile()},
+ name: bp2buildWorkspaceTag,
+ description: "Creating Bazel symlink forest",
+ config: config,
+ output: config.Bp2BuildWorkspaceMarkerFile(),
+ specificArgs: append(baseArgs,
+ "--symlink_forest_marker", config.Bp2BuildWorkspaceMarkerFile(),
+ ),
},
{
name: jsonModuleGraphTag,
description: fmt.Sprintf("generating the Soong module graph at %s", config.ModuleGraphFile()),
config: config,
output: config.ModuleGraphFile(),
- specificArgs: []string{
+ specificArgs: append(baseArgs,
"--module_graph_file", config.ModuleGraphFile(),
"--module_actions_file", config.ModuleActionsFile(),
- },
+ ),
},
{
- name: queryviewTag,
- description: fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
- config: config,
- output: config.QueryviewMarkerFile(),
- specificArgs: []string{"--bazel_queryview_dir", queryviewDir},
+ name: queryviewTag,
+ description: fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
+ config: config,
+ output: config.QueryviewMarkerFile(),
+ specificArgs: append(baseArgs,
+ "--bazel_queryview_dir", queryviewDir,
+ ),
},
{
- name: apiBp2buildTag,
- description: fmt.Sprintf("generating BUILD files for API contributions at %s", apiBp2buildDir),
- config: config,
- output: config.ApiBp2buildMarkerFile(),
- specificArgs: []string{"--bazel_api_bp2build_dir", apiBp2buildDir},
+ name: apiBp2buildTag,
+ description: fmt.Sprintf("generating BUILD files for API contributions at %s", apiBp2buildDir),
+ config: config,
+ output: config.ApiBp2buildMarkerFile(),
+ specificArgs: append(baseArgs,
+ "--bazel_api_bp2build_dir", apiBp2buildDir,
+ ),
},
{
- name: soongDocsTag,
- description: fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
- config: config,
- output: config.SoongDocsHtml(),
- specificArgs: []string{"--soong_docs", config.SoongDocsHtml()},
+ name: soongDocsTag,
+ description: fmt.Sprintf("generating Soong docs at %s", config.SoongDocsHtml()),
+ config: config,
+ output: config.SoongDocsHtml(),
+ specificArgs: append(baseArgs,
+ "--soong_docs", config.SoongDocsHtml(),
+ ),
},
}
diff --git a/ui/metrics/BUILD.bazel b/ui/metrics/BUILD.bazel
index 15ebb88..2dc1ab6 100644
--- a/ui/metrics/BUILD.bazel
+++ b/ui/metrics/BUILD.bazel
@@ -16,7 +16,7 @@
py_proto_library(
name = "metrics-py-proto",
- visibility = ["//build/bazel/scripts/incremental_build:__pkg__"],
+ visibility = ["//build/bazel/scripts:__subpackages__"],
deps = [":metrics-proto"],
)