Merge "Use OutputFilesProvider on prebuilt_etc" into main
diff --git a/Android.bp b/Android.bp
index b1db8e9..2c0ef47 100644
--- a/Android.bp
+++ b/Android.bp
@@ -104,6 +104,7 @@
// Instantiate the dex_bootjars singleton module.
dex_bootjars {
name: "dex_bootjars",
+ no_full_install: true,
}
// Pseudo-test that's run on checkbuilds to ensure that get_clang_version can
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index af9123e..919cb01 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -1366,4 +1366,89 @@
android.AssertStringDoesContain(t, "test", command, "--test-stub-classpath="+nonUpdatableTestStubs)
}
+func TestBootclasspathFragmentProtoContainsMinSdkVersion(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithBootclasspathFragment,
+ prepareForTestWithMyapex,
+ // Configure bootclasspath jars to ensure that hidden API encoding is performed on them.
+ java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
+ // Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
+ // is disabled.
+ android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+
+ java.PrepareForTestWithJavaSdkLibraryFiles,
+ java.FixtureWithLastReleaseApis("foo", "bar"),
+ ).RunTestWithBp(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: [
+ "mybootclasspathfragment",
+ ],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_sdk_library {
+ name: "foo",
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {enabled: true},
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "33",
+ }
+
+ java_sdk_library {
+ name: "bar",
+ srcs: ["b.java"],
+ shared_library: false,
+ public: {enabled: true},
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "34",
+ }
+
+ bootclasspath_fragment {
+ name: "mybootclasspathfragment",
+ contents: [
+ "foo",
+ "bar",
+ ],
+ apex_available: [
+ "myapex",
+ ],
+ hidden_api: {
+ split_packages: ["*"],
+ },
+ }
+ `)
+
+ fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000")
+ classPathProtoContent := android.ContentFromFileRuleForTests(t, result.TestContext, fragment.Output("bootclasspath.pb.textproto"))
+ // foo
+ ensureContains(t, classPathProtoContent, `jars {
+path: "/apex/myapex/javalib/foo.jar"
+classpath: BOOTCLASSPATH
+min_sdk_version: "33"
+max_sdk_version: ""
+}
+`)
+ // bar
+ ensureContains(t, classPathProtoContent, `jars {
+path: "/apex/myapex/javalib/bar.jar"
+classpath: BOOTCLASSPATH
+min_sdk_version: "34"
+max_sdk_version: ""
+}
+`)
+}
+
// TODO(b/177892522) - add test for host apex.
diff --git a/cc/builder.go b/cc/builder.go
index 7a3394a..8719d4f 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -485,7 +485,7 @@
coverageFiles = make(android.Paths, 0, len(srcFiles))
}
var kytheFiles android.Paths
- if flags.emitXrefs {
+ if flags.emitXrefs && ctx.Module() == ctx.PrimaryModule() {
kytheFiles = make(android.Paths, 0, len(srcFiles))
}
@@ -664,7 +664,7 @@
})
// Register post-process build statements (such as for tidy or kythe).
- if emitXref {
+ if emitXref && ctx.Module() == ctx.PrimaryModule() {
kytheFile := android.ObjPathWithExt(ctx, subdir, srcFile, "kzip")
ctx.Build(pctx, android.BuildParams{
Rule: kytheExtract,
diff --git a/cc/cmake_main.txt b/cc/cmake_main.txt
index deb1de1..e9177d6 100644
--- a/cc/cmake_main.txt
+++ b/cc/cmake_main.txt
@@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.18)
project(<<.M.Name>> CXX)
set(CMAKE_CXX_STANDARD 20)
+enable_testing()
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(AddAidlLibrary)
diff --git a/cc/cmake_module_cc.txt b/cc/cmake_module_cc.txt
index 488e5e1..693406d 100644
--- a/cc/cmake_module_cc.txt
+++ b/cc/cmake_module_cc.txt
@@ -8,15 +8,24 @@
(getLinkerProperties .M).Header_libs
(getExtraLibs .M)
) .Pprop.LibraryMapping>>
+<<$moduleType := getModuleType .M>>
+<<$moduleTypeCmake := "executable">>
+<<if eq $moduleType "library">>
+<<$moduleTypeCmake = "library">>
+<<end>>
# <<.M.Name>>
<<if $srcs>>
<<setList .M.Name "_SRCS" "${ANDROID_BUILD_TOP}/" (toStrings $srcs)>>
-add_<<getModuleType .M>>(<<.M.Name>> ${<<.M.Name>>_SRCS})
+add_<<$moduleTypeCmake>>(<<.M.Name>> ${<<.M.Name>>_SRCS})
<<- else>>
-add_<<getModuleType .M>>(<<.M.Name>> INTERFACE)
+add_<<$moduleTypeCmake>>(<<.M.Name>> INTERFACE)
<<- end>>
-add_<<getModuleType .M>>(android::<<.M.Name>> ALIAS <<.M.Name>>)
+<<- if eq $moduleType "library">>
+add_library(android::<<.M.Name>> ALIAS <<.M.Name>>)
+<<- else if eq $moduleType "test">>
+add_test(NAME <<.M.Name>> COMMAND <<.M.Name>>)
+<<- end>>
<<print "">>
<<- if $includeDirs>>
diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go
index 9ac6350..ad7beed 100644
--- a/cc/cmake_snapshot.go
+++ b/cc/cmake_snapshot.go
@@ -488,9 +488,9 @@
case *libraryDecorator:
return "library"
case *testBinary:
- return "executable"
+ return "test"
case *benchmarkDecorator:
- return "executable"
+ return "test"
}
panic(fmt.Sprintf("Unexpected module type: %T", m.linker))
}
diff --git a/cmd/release_config/build_flag/main.go b/cmd/release_config/build_flag/main.go
index f74784b..5d183ee 100644
--- a/cmd/release_config/build_flag/main.go
+++ b/cmd/release_config/build_flag/main.go
@@ -163,6 +163,7 @@
for _, fa := range configs.FlagArtifacts {
args = append(args, *fa.FlagDeclaration.Name)
}
+ slices.Sort(args)
}
var maxVariableNameLen, maxReleaseNameLen int
@@ -232,7 +233,7 @@
} else {
outputOneLine(arg, config.Name, "REDACTED", "%s")
}
- if isTrace {
+ if err == nil && isTrace {
for _, trace := range config.FlagArtifacts[arg].Traces {
fmt.Printf(" => \"%s\" in %s\n", rc_lib.MarshalValue(trace.Value), *trace.Source)
}
@@ -244,6 +245,8 @@
func SetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, args []string) error {
var valueDir string
+ var redacted bool
+ var value string
if len(commonFlags.targetReleases) > 1 {
return fmt.Errorf("set command only allows one --release argument. Got: %s", strings.Join(commonFlags.targetReleases, " "))
}
@@ -251,13 +254,20 @@
setFlags := flag.NewFlagSet("set", flag.ExitOnError)
setFlags.StringVar(&valueDir, "dir", "", "Directory in which to place the value")
+ setFlags.BoolVar(&redacted, "redacted", false, "Whether the flag should be redacted")
setFlags.Parse(args)
setArgs := setFlags.Args()
- if len(setArgs) != 2 {
+ if redacted {
+ if len(setArgs) != 1 {
+ return fmt.Errorf("set command expected '--redacted=true flag', got: --redacted=true %s", strings.Join(setArgs, " "))
+ }
+ } else if len(setArgs) != 2 {
return fmt.Errorf("set command expected flag and value, got: %s", strings.Join(setArgs, " "))
}
name := setArgs[0]
- value := setArgs[1]
+ if !redacted {
+ value = setArgs[1]
+ }
release, err := configs.GetReleaseConfig(targetRelease)
targetRelease = release.Name
if err != nil {
@@ -278,9 +288,30 @@
valueDir = mapDir
}
+ var updatedFiles []string
+ rcPath := filepath.Join(valueDir, "release_configs", fmt.Sprintf("%s.textproto", targetRelease))
+ // Create the release config declaration only if necessary.
+ if _, err = os.Stat(rcPath); err != nil {
+ if err = os.MkdirAll(filepath.Dir(rcPath), 0775); err != nil {
+ return err
+ }
+ rcValue := &rc_proto.ReleaseConfig{
+ Name: proto.String(targetRelease),
+ }
+ err = rc_lib.WriteMessage(rcPath, rcValue)
+ if err != nil {
+ return err
+ }
+ updatedFiles = append(updatedFiles, rcPath)
+ }
+
flagValue := &rc_proto.FlagValue{
- Name: proto.String(name),
- Value: rc_lib.UnmarshalValue(value),
+ Name: proto.String(name),
+ }
+ if redacted {
+ flagValue.Redacted = proto.Bool(true)
+ } else {
+ flagValue.Value = rc_lib.UnmarshalValue(value)
}
flagPath := filepath.Join(valueDir, "flag_values", targetRelease, fmt.Sprintf("%s.textproto", name))
err = rc_lib.WriteMessage(flagPath, flagValue)
@@ -293,11 +324,12 @@
if err != nil {
return err
}
- err = GetCommand(configs, commonFlags, cmd, args[0:1])
+ err = GetCommand(configs, commonFlags, cmd, []string{name})
if err != nil {
return err
}
- fmt.Printf("Updated: %s\n", flagPath)
+ updatedFiles = append(updatedFiles, flagPath)
+ fmt.Printf("Added/Updated: %s\n", strings.Join(updatedFiles, " "))
return nil
}
diff --git a/cmd/release_config/release_config_lib/util.go b/cmd/release_config/release_config_lib/util.go
index b8824d1..0a19efe 100644
--- a/cmd/release_config/release_config_lib/util.go
+++ b/cmd/release_config/release_config_lib/util.go
@@ -83,6 +83,11 @@
// error: any error encountered.
func WriteFormattedMessage(path, format string, message proto.Message) (err error) {
var data []byte
+ if _, err := os.Stat(filepath.Dir(path)); err != nil {
+ if err = os.MkdirAll(filepath.Dir(path), 0775); err != nil {
+ return err
+ }
+ }
switch format {
case "json":
data, err = json.MarshalIndent(message, "", " ")
diff --git a/java/base.go b/java/base.go
index b4f800b..1a6584b 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1852,7 +1852,7 @@
classes := android.PathForModuleOut(ctx, "javac", jarName).OutputPath
TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps)
- if ctx.Config().EmitXrefRules() {
+ if ctx.Config().EmitXrefRules() && ctx.Module() == ctx.PrimaryModule() {
extractionFile := android.PathForModuleOut(ctx, kzipName)
emitXrefRule(ctx, extractionFile, idx, srcFiles, srcJars, flags, extraJarDeps)
j.kytheFiles = append(j.kytheFiles, extractionFile)
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 07bc5c1..18a5dae 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -128,19 +128,21 @@
return m.Name() == configuredJars.Jar(i)
}, func(m android.Module) {
if s, ok := m.(*SdkLibrary); ok {
+ minSdkVersion := s.MinSdkVersion(ctx)
+ maxSdkVersion := s.MaxSdkVersion(ctx)
// TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current"
- if s.minSdkVersion.Specified() {
- if s.minSdkVersion.IsCurrent() {
+ if minSdkVersion.Specified() {
+ if minSdkVersion.IsCurrent() {
jar.minSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
} else {
- jar.minSdkVersion = s.minSdkVersion.String()
+ jar.minSdkVersion = minSdkVersion.String()
}
}
- if s.maxSdkVersion.Specified() {
- if s.maxSdkVersion.IsCurrent() {
+ if maxSdkVersion.Specified() {
+ if maxSdkVersion.IsCurrent() {
jar.maxSdkVersion = ctx.Config().DefaultAppTargetSdk(ctx).String()
} else {
- jar.maxSdkVersion = s.maxSdkVersion.String()
+ jar.maxSdkVersion = maxSdkVersion.String()
}
}
}
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 832b850..57aaa1a 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -312,10 +312,6 @@
dexpreopt.RegisterToolDeps(ctx)
}
-func (d *dexpreopter) odexOnSystemOther(ctx android.ModuleContext, libName string, installPath android.InstallPath) bool {
- return dexpreopt.OdexOnSystemOtherByName(libName, android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
-}
-
// Returns the install path of the dex jar of a module.
//
// Do not rely on `ApexInfo.ApexVariationName` because it can be something like "apex1000", rather
@@ -545,12 +541,21 @@
// Use the path of the dex file to determine the library name
isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(dexJarStem)
+ partition := d.installPath.Partition()
for _, install := range dexpreoptRule.Installs() {
// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
+ if strings.HasPrefix(installDir, partition+"/") {
+ installDir = strings.TrimPrefix(installDir, partition+"/")
+ } else {
+ // If the partition for the installDir is different from the install partition, set the
+ // partition empty to install the dexpreopt files to the desired partition.
+ // TODO(b/346439786): Define and use the dexpreopt module type to avoid this mismatch.
+ partition = ""
+ }
installBase := filepath.Base(install.To)
arch := filepath.Base(installDir)
- installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+ installPath := android.PathForModuleInPartitionInstall(ctx, partition, installDir)
isProfile := strings.HasSuffix(installBase, ".prof")
if isProfile {
@@ -584,6 +589,37 @@
}
}
+func getModuleInstallPathInfo(ctx android.ModuleContext, fullInstallPath string) (android.InstallPath, string, string) {
+ installPath := android.PathForModuleInstall(ctx)
+ installDir, installBase := filepath.Split(strings.TrimPrefix(fullInstallPath, "/"))
+
+ if !strings.HasPrefix(installDir, installPath.Partition()+"/") {
+ // Return empty filename if the install partition is not for the target image.
+ return installPath, "", ""
+ }
+ relDir, err := filepath.Rel(installPath.Partition(), installDir)
+ if err != nil {
+ panic(err)
+ }
+ return installPath, relDir, installBase
+}
+
+// RuleBuilder.Install() adds output-to-install copy pairs to a list for Make. To share this
+// information with PackagingSpec in soong, call PackageFile for them.
+// The install path and the target install partition of the module must be the same.
+func packageFile(ctx android.ModuleContext, install android.RuleBuilderInstall) {
+ installPath, relDir, name := getModuleInstallPathInfo(ctx, install.To)
+ // Empty name means the install partition is not for the target image.
+ // For the system image, files for "apex" and "system_other" are skipped here.
+ // The skipped "apex" files are for testing only, for example,
+ // "/apex/art_boot_images/javalib/x86/boot.vdex".
+ // TODO(b/320196894): Files for "system_other" are skipped because soong creates the system
+ // image only for now.
+ if name != "" {
+ ctx.PackageFile(installPath.Join(ctx, relDir), name, install.From)
+ }
+}
+
func (d *dexpreopter) DexpreoptBuiltInstalledForApex() []dexpreopterInstall {
return d.builtInstalledForApex
}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 7229ca0..defa82c 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -612,6 +612,9 @@
profileInstalls: profileInstalls,
profileLicenseMetadataFile: android.OptionalPathForPath(ctx.LicenseMetadataFile()),
})
+ for _, install := range profileInstalls {
+ packageFile(ctx, install)
+ }
}
}
@@ -929,6 +932,35 @@
return apexNameToApexExportsInfoMap
}
+func packageFileForTargetImage(ctx android.ModuleContext, image *bootImageVariant) {
+ if image.target.Os != ctx.Os() {
+ // This is not for the target device.
+ return
+ }
+
+ for _, install := range image.installs {
+ packageFile(ctx, install)
+ }
+
+ for _, install := range image.vdexInstalls {
+ if image.target.Arch.ArchType.Name != ctx.DeviceConfig().DeviceArch() {
+ // Note that the vdex files are identical between architectures. If the target image is
+ // not for the primary architecture create symlinks to share the vdex of the primary
+ // architecture with the other architectures.
+ //
+ // Assuming that the install path has the architecture name with it, replace the
+ // architecture name with the primary architecture name to find the source vdex file.
+ installPath, relDir, name := getModuleInstallPathInfo(ctx, install.To)
+ if name != "" {
+ srcRelDir := strings.Replace(relDir, image.target.Arch.ArchType.Name, ctx.DeviceConfig().DeviceArch(), 1)
+ ctx.InstallSymlink(installPath.Join(ctx, relDir), name, installPath.Join(ctx, srcRelDir, name))
+ }
+ } else {
+ packageFile(ctx, install)
+ }
+ }
+}
+
// Generate boot image build rules for a specific target.
func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, profile android.Path) bootImageVariantOutputs {
@@ -1123,6 +1155,7 @@
image.installs = rule.Installs()
image.vdexInstalls = vdexInstalls
image.unstrippedInstalls = unstrippedInstalls
+ packageFileForTargetImage(ctx, image)
// Only set the licenseMetadataFile from the active module.
if isActiveModule(ctx, ctx.Module()) {
diff --git a/ui/build/build.go b/ui/build/build.go
index 9a9eccd..03d8392 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -21,7 +21,6 @@
"path/filepath"
"sync"
"text/template"
- "time"
"android/soong/ui/metrics"
)
@@ -66,9 +65,12 @@
// (to allow for source control that uses something other than numbers),
// but must be a single word and a valid file name.
//
- // If no BUILD_NUMBER is set, create a useful "I am an engineering build
- // from this date/time" value. Make it start with a non-digit so that
- // anyone trying to parse it as an integer will probably get "0".
+ // If no BUILD_NUMBER is set, create a useful "I am an engineering build"
+ // value. Make it start with a non-digit so that anyone trying to parse
+ // it as an integer will probably get "0". This value used to contain
+ // a timestamp, but now that more dependencies are tracked in order to
+ // reduce the importance of `m installclean`, changing it every build
+ // causes unnecessary rebuilds for local development.
buildNumber, ok := config.environ.Get("BUILD_NUMBER")
if ok {
writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", buildNumber)
@@ -77,7 +79,7 @@
if username, ok = config.environ.Get("BUILD_USERNAME"); !ok {
ctx.Fatalln("Missing BUILD_USERNAME")
}
- buildNumber = fmt.Sprintf("eng.%.6s.%s", username, time.Now().Format("20060102.150405" /* YYYYMMDD.HHMMSS */))
+ buildNumber = fmt.Sprintf("eng.%.6s.00000000.000000", username)
writeValueIfChanged(ctx, config, config.OutDir(), "file_name_tag.txt", username)
}
// Write the build number to a file so it can be read back in