Merge "Introduce module type to autogenerate RROS" into main
diff --git a/android/module.go b/android/module.go
index ce995ad..3bf4f0c 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2450,6 +2450,8 @@
return proptools.ConfigurableValueString(v)
case "bool":
return proptools.ConfigurableValueBool(v == "true")
+ case "string_list":
+ return proptools.ConfigurableValueStringList(strings.Split(v, " "))
default:
panic("unhandled soong config variable type: " + ty)
}
diff --git a/android/neverallow.go b/android/neverallow.go
index 42fecaa..b55baae 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -55,7 +55,7 @@
AddNeverAllowRules(createJavaDeviceForHostRules()...)
AddNeverAllowRules(createCcSdkVariantRules()...)
AddNeverAllowRules(createUncompressDexRules()...)
- AddNeverAllowRules(createInitFirstStageRules()...)
+ AddNeverAllowRules(createInstallInRootAllowingRules()...)
AddNeverAllowRules(createProhibitFrameworkAccessRules()...)
AddNeverAllowRules(createCcStubsRule())
AddNeverAllowRules(createProhibitHeaderOnlyRule())
@@ -236,15 +236,16 @@
}
}
-func createInitFirstStageRules() []Rule {
+func createInstallInRootAllowingRules() []Rule {
return []Rule{
NeverAllow().
Without("name", "init_first_stage_defaults").
Without("name", "init_first_stage").
Without("name", "init_first_stage.microdroid").
+ Without("name", "librecovery_ui_ext").
With("install_in_root", "true").
NotModuleType("prebuilt_root").
- Because("install_in_root is only for init_first_stage."),
+ Because("install_in_root is only for init_first_stage or librecovery_ui_ext."),
}
}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index a157386..83f8b99 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -488,21 +488,15 @@
Inputs(depFiles.Paths())
}
-// BuildWithNinjaVars adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
-// Outputs. This function will not escape Ninja variables, so it may be used to write sandbox manifests using Ninja variables.
-func (r *RuleBuilder) BuildWithUnescapedNinjaVars(name string, desc string) {
- r.build(name, desc, false)
-}
-
// Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for
// Outputs.
func (r *RuleBuilder) Build(name string, desc string) {
- r.build(name, desc, true)
+ r.build(name, desc)
}
var sandboxEnvOnceKey = NewOnceKey("sandbox_environment_variables")
-func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString bool) {
+func (r *RuleBuilder) build(name string, desc string) {
name = ninjaNameEscape(name)
if len(r.missingDeps) > 0 {
@@ -765,30 +759,7 @@
if err != nil {
ReportPathErrorf(r.ctx, "sbox manifest failed to marshal: %q", err)
}
- if ninjaEscapeCommandString {
- WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
- } else {
- // We need to have a rule to write files that is
- // defined on the RuleBuilder's pctx in order to
- // write Ninja variables in the string.
- // The WriteFileRule function above rule can only write
- // raw strings because it is defined on the android
- // package's pctx, and it can't access variables defined
- // in another context.
- r.ctx.Build(r.pctx, BuildParams{
- Rule: r.ctx.Rule(r.pctx, "unescapedWriteFile", blueprint.RuleParams{
- Command: `rm -rf ${out} && cat ${out}.rsp > ${out}`,
- Rspfile: "${out}.rsp",
- RspfileContent: "${content}",
- Description: "write file",
- }, "content"),
- Output: r.sboxManifestPath,
- Description: "write sbox manifest " + r.sboxManifestPath.Base(),
- Args: map[string]string{
- "content": string(pbText),
- },
- })
- }
+ WriteFileRule(r.ctx, r.sboxManifestPath, string(pbText))
// Generate a new string to use as the command line of the sbox rule. This uses
// a RuleBuilderCommand as a convenience method of building the command line, then
@@ -882,9 +853,7 @@
pool = localPool
}
- if ninjaEscapeCommandString {
- commandString = proptools.NinjaEscape(commandString)
- }
+ commandString = proptools.NinjaEscape(commandString)
args_vars := make([]string, len(r.args))
i := 0
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index 6a8a964..e1a1e08 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -475,10 +475,9 @@
Srcs []string
Flags []string
- Restat bool
- Sbox bool
- Sbox_inputs bool
- Unescape_ninja_vars bool
+ Restat bool
+ Sbox bool
+ Sbox_inputs bool
}
}
@@ -498,7 +497,7 @@
testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, t.properties.Flags,
out, outDep, outDir,
- manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs, t.properties.Unescape_ninja_vars,
+ manifestPath, t.properties.Restat, t.properties.Sbox, t.properties.Sbox_inputs,
rspFile, rspFileContents, rspFile2, rspFileContents2)
}
@@ -523,14 +522,14 @@
manifestPath := PathForOutput(ctx, "singleton/sbox.textproto")
testRuleBuilder_Build(ctx, in, implicit, orderOnly, validation, nil, out, outDep, outDir,
- manifestPath, true, false, false, false,
+ manifestPath, true, false, false,
rspFile, rspFileContents, rspFile2, rspFileContents2)
}
func testRuleBuilder_Build(ctx BuilderContext, in Paths, implicit, orderOnly, validation Path,
flags []string,
out, outDep, outDir, manifestPath WritablePath,
- restat, sbox, sboxInputs, unescapeNinjaVars bool,
+ restat, sbox, sboxInputs bool,
rspFile WritablePath, rspFileContents Paths, rspFile2 WritablePath, rspFileContents2 Paths) {
rule := NewRuleBuilder(pctx_ruleBuilderTest, ctx)
@@ -558,11 +557,7 @@
rule.Restat()
}
- if unescapeNinjaVars {
- rule.BuildWithUnescapedNinjaVars("rule", "desc")
- } else {
- rule.Build("rule", "desc")
- }
+ rule.Build("rule", "desc")
}
var prepareForRuleBuilderTest = FixtureRegisterWithContext(func(ctx RegistrationContext) {
@@ -777,48 +772,3 @@
})
}
}
-
-func TestRuleBuilderWithNinjaVarEscaping(t *testing.T) {
- bp := `
- rule_builder_test {
- name: "foo_sbox_escaped",
- flags: ["${cmdFlags}"],
- sbox: true,
- sbox_inputs: true,
- }
- rule_builder_test {
- name: "foo_sbox_unescaped",
- flags: ["${cmdFlags}"],
- sbox: true,
- sbox_inputs: true,
- unescape_ninja_vars: true,
- }
- `
- result := GroupFixturePreparers(
- prepareForRuleBuilderTest,
- FixtureWithRootAndroidBp(bp),
- ).RunTest(t)
-
- escapedNinjaMod := result.ModuleForTests("foo_sbox_escaped", "").Output("sbox.textproto")
- AssertStringEquals(t, "expected rule", "android/soong/android.rawFileCopy", escapedNinjaMod.Rule.String())
- AssertStringDoesContain(
- t,
- "",
- ContentFromFileRuleForTests(t, result.TestContext, escapedNinjaMod),
- "${cmdFlags}",
- )
-
- unescapedNinjaMod := result.ModuleForTests("foo_sbox_unescaped", "").Rule("unescapedWriteFile")
- AssertStringDoesContain(
- t,
- "",
- unescapedNinjaMod.BuildParams.Args["content"],
- "${cmdFlags}",
- )
- AssertStringDoesNotContain(
- t,
- "",
- unescapedNinjaMod.BuildParams.Args["content"],
- "$${cmdFlags}",
- )
-}
diff --git a/android/selects_test.go b/android/selects_test.go
index 90d7091..1397ed8 100644
--- a/android/selects_test.go
+++ b/android/selects_test.go
@@ -1031,6 +1031,54 @@
my_string_list: &[]string{"d2", "e2", "f2", "a1", "b1", "c1"},
},
},
+ {
+ name: "string list variables",
+ bp: `
+my_module_type {
+ name: "foo",
+ my_string_list: ["a"] + select(soong_config_variable("my_namespace", "my_var"), {
+ any @ my_var: my_var,
+ default: [],
+ }),
+}
+`,
+ vendorVars: map[string]map[string]string{
+ "my_namespace": {
+ "my_var": "b c",
+ },
+ },
+ vendorVarTypes: map[string]map[string]string{
+ "my_namespace": {
+ "my_var": "string_list",
+ },
+ },
+ provider: selectsTestProvider{
+ my_string_list: &[]string{"a", "b", "c"},
+ },
+ },
+ {
+ name: "string list variables don't match string matchers",
+ bp: `
+my_module_type {
+ name: "foo",
+ my_string_list: ["a"] + select(soong_config_variable("my_namespace", "my_var"), {
+ "foo": ["b"],
+ default: [],
+ }),
+}
+`,
+ vendorVars: map[string]map[string]string{
+ "my_namespace": {
+ "my_var": "b c",
+ },
+ },
+ vendorVarTypes: map[string]map[string]string{
+ "my_namespace": {
+ "my_var": "string_list",
+ },
+ },
+ expectedError: `Expected all branches of a select on condition soong_config_variable\("my_namespace", "my_var"\) to have type string_list, found string`,
+ },
}
for _, tc := range testCases {
diff --git a/apex/apex.go b/apex/apex.go
index 0b56bf8..0e40d7c 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -434,6 +434,7 @@
archProperties apexArchBundleProperties
overridableProperties overridableProperties
vndkProperties apexVndkProperties // only for apex_vndk modules
+ testProperties apexTestProperties // only for apex_test modules
///////////////////////////////////////////////////////////////////////////////////////////
// Inputs
@@ -1296,6 +1297,23 @@
return proptools.BoolDefault(a.properties.Platform_apis, false)
}
+type apexValidationType int
+
+const (
+ hostApexVerifier apexValidationType = iota
+ apexSepolicyTests
+)
+
+func (a *apexBundle) skipValidation(validationType apexValidationType) bool {
+ switch validationType {
+ case hostApexVerifier:
+ return proptools.Bool(a.testProperties.Skip_validations.Host_apex_verifier)
+ case apexSepolicyTests:
+ return proptools.Bool(a.testProperties.Skip_validations.Apex_sepolicy_tests)
+ }
+ panic("Unknown validation type")
+}
+
// getCertString returns the name of the cert that should be used to sign this APEX. This is
// basically from the "certificate" property, but could be overridden by the device config.
func (a *apexBundle) getCertString(ctx android.BaseModuleContext) string {
@@ -2427,10 +2445,14 @@
return module
}
-func ApexBundleFactory(testApex bool) android.Module {
- bundle := newApexBundle()
- bundle.testApex = testApex
- return bundle
+type apexTestProperties struct {
+ // Boolean flags for validation checks. Test APEXes can turn on/off individual checks.
+ Skip_validations struct {
+ // Skips `Apex_sepolicy_tests` check if true
+ Apex_sepolicy_tests *bool
+ // Skips `Host_apex_verifier` check if true
+ Host_apex_verifier *bool
+ }
}
// apex_test is an APEX for testing. The difference from the ordinary apex module type is that
@@ -2438,6 +2460,7 @@
func TestApexBundleFactory() android.Module {
bundle := newApexBundle()
bundle.testApex = true
+ bundle.AddProperties(&bundle.testProperties)
return bundle
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 5b5fe5f..6e92959 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -7101,6 +7101,51 @@
`)
}
+func TestApexValidation_TestApexCanSkipInitRcCheck(t *testing.T) {
+ t.Parallel()
+ ctx := testApex(t, `
+ apex_test {
+ name: "myapex",
+ key: "myapex.key",
+ skip_validations: {
+ host_apex_verifier: true,
+ },
+ updatable: false,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+
+ validations := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk").Validations.Strings()
+ if android.SuffixInList(validations, "host_apex_verifier.timestamp") {
+ t.Error("should not run host_apex_verifier")
+ }
+}
+
+func TestApexValidation_TestApexCheckInitRc(t *testing.T) {
+ t.Parallel()
+ ctx := testApex(t, `
+ apex_test {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: false,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+
+ validations := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk").Validations.Strings()
+ if !android.SuffixInList(validations, "host_apex_verifier.timestamp") {
+ t.Error("should run host_apex_verifier")
+ }
+}
+
func TestOverrideApex(t *testing.T) {
t.Parallel()
ctx := testApex(t, `
diff --git a/apex/builder.go b/apex/builder.go
index d0acc8d..e5ae106 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -924,14 +924,14 @@
var validations android.Paths
validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile, imageDir))
// TODO(b/279688635) deapexer supports [ext4]
- if !a.testApex && suffix == imageApexSuffix && ext4 == a.payloadFsType {
+ if !a.skipValidation(apexSepolicyTests) && suffix == imageApexSuffix && ext4 == a.payloadFsType {
validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile))
}
if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 {
validations = append(validations,
runApexElfCheckerUnwanted(ctx, unsignedOutputFile, a.properties.Unwanted_transitive_deps))
}
- if !a.testApex && android.InList(a.payloadFsType, []fsType{ext4, erofs}) {
+ if !a.skipValidation(hostApexVerifier) && android.InList(a.payloadFsType, []fsType{ext4, erofs}) {
validations = append(validations, runApexHostVerifier(ctx, a, unsignedOutputFile))
}
ctx.Build(pctx, android.BuildParams{
@@ -1220,7 +1220,7 @@
// $ deapexer list -Z {apex_file} > {file_contexts}
// $ apex_sepolicy_tests -f {file_contexts}
func runApexSepolicyTests(ctx android.ModuleContext, apexFile android.Path) android.Path {
- timestamp := android.PathForModuleOut(ctx, "sepolicy_tests.timestamp")
+ timestamp := android.PathForModuleOut(ctx, "apex_sepolicy_tests.timestamp")
ctx.Build(pctx, android.BuildParams{
Rule: apexSepolicyTestsRule,
Input: apexFile,
diff --git a/cc/config/global.go b/cc/config/global.go
index 6984ea4..27aac95 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -296,6 +296,7 @@
// Allow using VLA CXX extension.
"-Wno-vla-cxx-extension",
+ "-Wno-cast-function-type-mismatch",
}
noOverride64GlobalCflags = []string{}
@@ -384,7 +385,7 @@
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r530567"
+ ClangDefaultVersion = "clang-r536225"
ClangDefaultShortVersion = "19"
// Directories with warnings from Android.bp files.
diff --git a/cc/linker.go b/cc/linker.go
index f9d58ea..b96d139 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -235,13 +235,16 @@
// Generate compact dynamic relocation table, default true.
Pack_relocations *bool `android:"arch_variant"`
- // local file name to pass to the linker as --version-script
+ // local file name to pass to the linker as --version-script. Not supported on darwin, and will fail to build
+ // if provided to the darwin variant of a module.
Version_script *string `android:"path,arch_variant"`
- // local file name to pass to the linker as --dynamic-list
+ // local file name to pass to the linker as --dynamic-list. Not supported on darwin, and will fail to build
+ // if provided to the darwin variant of a module.
Dynamic_list *string `android:"path,arch_variant"`
- // local files to pass to the linker as --script
+ // local files to pass to the linker as --script. Not supported on darwin or windows, and will fail to build
+ // if provided to the darwin or windows variant of a module.
Linker_scripts []string `android:"path,arch_variant"`
// list of static libs that should not be used to build this module
@@ -560,7 +563,7 @@
if versionScript.Valid() {
if ctx.Darwin() {
- ctx.PropertyErrorf("version_script", "Not supported on Darwin")
+ ctx.AddMissingDependencies([]string{"version_script_not_supported_on_darwin"})
} else {
flags.Local.LdFlags = append(flags.Local.LdFlags,
config.VersionScriptFlagPrefix+versionScript.String())
@@ -578,7 +581,7 @@
dynamicList := android.OptionalPathForModuleSrc(ctx, linker.Properties.Dynamic_list)
if dynamicList.Valid() {
if ctx.Darwin() {
- ctx.PropertyErrorf("dynamic_list", "Not supported on Darwin")
+ ctx.AddMissingDependencies([]string{"dynamic_list_not_supported_on_darwin"})
} else {
flags.Local.LdFlags = append(flags.Local.LdFlags,
"-Wl,--dynamic-list,"+dynamicList.String())
@@ -587,13 +590,17 @@
}
linkerScriptPaths := android.PathsForModuleSrc(ctx, linker.Properties.Linker_scripts)
- if len(linkerScriptPaths) > 0 && (ctx.Darwin() || ctx.Windows()) {
- ctx.PropertyErrorf("linker_scripts", "Only supported for ELF files")
- } else {
- for _, linkerScriptPath := range linkerScriptPaths {
- flags.Local.LdFlags = append(flags.Local.LdFlags,
- "-Wl,--script,"+linkerScriptPath.String())
- flags.LdFlagsDeps = append(flags.LdFlagsDeps, linkerScriptPath)
+ if len(linkerScriptPaths) > 0 {
+ if ctx.Darwin() {
+ ctx.AddMissingDependencies([]string{"linker_scripts_not_supported_on_darwin"})
+ } else if ctx.Windows() {
+ ctx.PropertyErrorf("linker_scripts", "Only supported for ELF files")
+ } else {
+ for _, linkerScriptPath := range linkerScriptPaths {
+ flags.Local.LdFlags = append(flags.Local.LdFlags,
+ "-Wl,--script,"+linkerScriptPath.String())
+ flags.LdFlagsDeps = append(flags.LdFlagsDeps, linkerScriptPath)
+ }
}
}
}
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index c8e27e5..0ffec26 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -330,9 +330,17 @@
cmd.Flag("--dynamic_partition_size")
}
+ // If you don't provide a salt, avbtool will use random bytes for the salt.
+ // This is bad for determinism (cached builds and diff tests are affected), so instead,
+ // we try to provide a salt. The requirements for a salt are not very clear, one aspect of it
+ // is that if it's unpredictable, attackers trying to change the contents of a partition need
+ // to find a new hash collision every release, because the salt changed.
if kernel != nil {
cmd.Textf(`--salt $(sha256sum "%s" | cut -d " " -f 1)`, kernel.String())
cmd.Implicit(kernel)
+ } else {
+ cmd.Textf(`--salt $(sha256sum "%s" "%s" | cut -d " " -f 1 | tr -d '\n')`, ctx.Config().BuildNumberFile(ctx), ctx.Config().Getenv("BUILD_DATETIME_FILE"))
+ cmd.OrderOnly(ctx.Config().BuildNumberFile(ctx))
}
cmd.FlagWithArg("--partition_name ", b.bootImageType.String())