diff options
| -rw-r--r-- | android/bazel.go | 47 | ||||
| -rw-r--r-- | android/paths.go | 198 | ||||
| -rw-r--r-- | android/testing.go | 29 | ||||
| -rw-r--r-- | cc/cc.go | 6 | ||||
| -rw-r--r-- | cc/config/toolchain.go | 4 | ||||
| -rw-r--r-- | cc/pgo.go | 9 | ||||
| -rw-r--r-- | dexpreopt/config.go | 2 | ||||
| -rw-r--r-- | dexpreopt/testing.go | 14 | ||||
| -rw-r--r-- | java/app_test.go | 61 | ||||
| -rw-r--r-- | java/dexpreopt.go | 13 | ||||
| -rw-r--r-- | java/dexpreopt_bootjars.go | 26 | ||||
| -rw-r--r-- | java/dexpreopt_config.go | 51 | ||||
| -rw-r--r-- | java/java_test.go | 4 |
13 files changed, 387 insertions, 77 deletions
diff --git a/android/bazel.go b/android/bazel.go index 9b0642696..9a14e7062 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -127,10 +127,57 @@ var ( "system/core/libcutils": Bp2BuildDefaultTrueRecursively, "system/logging/liblog": Bp2BuildDefaultTrueRecursively, } + + // Per-module denylist to always opt modules out. + bp2buildModuleDoNotConvert = map[string]bool{ + "libBionicBenchmarksUtils": true, + "libbionic_spawn_benchmark": true, + "libc_jemalloc_wrapper": true, + "libc_bootstrap": true, + "libc_init_static": true, + "libc_init_dynamic": true, + "libc_tzcode": true, + "lib_dns": true, + "libc_freebsd": true, + "libc_freebsd_large_stack": true, + "libc_netbsd": true, + "libc_openbsd_ndk": true, + "libc_openbsd_large_stack": true, + "libc_openbsd": true, + "libc_gdtoa": true, + "libc_fortify": true, + "libc_bionic": true, + "libc_bionic_ndk": true, + "libc_bionic_systrace": true, + "libc_pthread": true, + "libc_syscalls": true, + "libc_aeabi": true, + "libc_ndk": true, + "libc_nopthread": true, + "libc_common": true, + "libc_static_dispatch": true, + "libc_dynamic_dispatch": true, + "libc_common_static": true, + "libc_common_shared": true, + "libc_unwind_static": true, + "libc_nomalloc": true, + "libasync_safe": true, + "libc_malloc_debug_backtrace": true, + "libsystemproperties": true, + "libdl_static": true, + "liblinker_main": true, + "liblinker_malloc": true, + "liblinker_debuggerd_stub": true, + "libbionic_tests_headers_posix": true, + } ) // ConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build. func (b *BazelModuleBase) ConvertWithBp2build(ctx BazelConversionPathContext) bool { + if bp2buildModuleDoNotConvert[ctx.Module().Name()] { + return false + } + // Ensure that the module type of this module has a bp2build converter. This // prevents mixed builds from using auto-converted modules just by matching // the package dir; it also has to have a bp2build mutator as well. diff --git a/android/paths.go b/android/paths.go index 0ed988a0f..127896104 100644 --- a/android/paths.go +++ b/android/paths.go @@ -174,14 +174,41 @@ type Path interface { // example, Rel on a PathsForModuleSrc would return the path relative to the module source // directory, and OutputPath.Join("foo").Rel() would return "foo". Rel() string -} + + // RelativeToTop returns a new path relative to the top, it is provided solely for use in tests. + // + // It is guaranteed to always return the same type as it is called on, e.g. if called on an + // InstallPath then the returned value can be converted to an InstallPath. + // + // A standard build has the following structure: + // ../top/ + // out/ - make install files go here. + // out/soong - this is the buildDir passed to NewTestConfig() + // ... - the source files + // + // This function converts a path so that it appears relative to the ../top/ directory, i.e. + // * Make install paths, which have the pattern "buildDir/../<path>" are converted into the top + // relative path "out/<path>" + // * Soong install paths and other writable paths, which have the pattern "buildDir/<path>" are + // converted into the top relative path "out/soong/<path>". + // * Source paths are already relative to the top. + // * Phony paths are not relative to anything. + // * toolDepPath have an absolute but known value in so don't need making relative to anything in + // order to test. + RelativeToTop() Path +} + +const ( + OutDir = "out" + OutSoongDir = OutDir + "/soong" +) // WritablePath is a type of path that can be used as an output for build rules. type WritablePath interface { Path // return the path to the build directory. - buildDir() string + getBuildDir() string // the writablePath method doesn't directly do anything, // but it allows a struct to distinguish between whether or not it implements the WritablePath interface @@ -271,6 +298,20 @@ func (p OptionalPath) String() string { // Paths is a slice of Path objects, with helpers to operate on the collection. type Paths []Path +// RelativeToTop creates a new Paths containing the result of calling Path.RelativeToTop on each +// item in this slice. +func (p Paths) RelativeToTop() Paths { + ensureTestOnly() + if p == nil { + return p + } + ret := make(Paths, len(p)) + for i, path := range p { + ret[i] = path.RelativeToTop() + } + return ret +} + func (paths Paths) containsPath(path Path) bool { for _, p := range paths { if p == path { @@ -910,6 +951,20 @@ func (p DirectorySortedPaths) PathsInDirectory(dir string) Paths { // WritablePaths is a slice of WritablePath, used for multiple outputs. type WritablePaths []WritablePath +// RelativeToTop creates a new WritablePaths containing the result of calling Path.RelativeToTop on +// each item in this slice. +func (p WritablePaths) RelativeToTop() WritablePaths { + ensureTestOnly() + if p == nil { + return p + } + ret := make(WritablePaths, len(p)) + for i, path := range p { + ret[i] = path.RelativeToTop().(WritablePath) + } + return ret +} + // Strings returns the string forms of the writable paths. func (p WritablePaths) Strings() []string { if p == nil { @@ -935,9 +990,8 @@ func (p WritablePaths) Paths() Paths { } type basePath struct { - path string - config Config - rel string + path string + rel string } func (p basePath) Ext() string { @@ -968,6 +1022,14 @@ func (p basePath) withRel(rel string) basePath { // SourcePath is a Path representing a file path rooted from SrcDir type SourcePath struct { basePath + + // The sources root, i.e. Config.SrcDir() + srcDir string +} + +func (p SourcePath) RelativeToTop() Path { + ensureTestOnly() + return p } var _ Path = SourcePath{} @@ -981,7 +1043,7 @@ func (p SourcePath) withRel(rel string) SourcePath { // code that is embedding ninja variables in paths func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) { p, err := validateSafePath(pathComponents...) - ret := SourcePath{basePath{p, ctx.Config(), ""}} + ret := SourcePath{basePath{p, ""}, ctx.Config().srcDir} if err != nil { return ret, err } @@ -997,7 +1059,7 @@ func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, e // pathForSource creates a SourcePath from pathComponents, but does not check that it exists. func pathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) { p, err := validatePath(pathComponents...) - ret := SourcePath{basePath{p, ctx.Config(), ""}} + ret := SourcePath{basePath{p, ""}, ctx.Config().srcDir} if err != nil { return ret, err } @@ -1091,7 +1153,7 @@ func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPa } func (p SourcePath) String() string { - return filepath.Join(p.config.srcDir, p.path) + return filepath.Join(p.srcDir, p.path) } // Join creates a new SourcePath with paths... joined with the current path. The @@ -1123,7 +1185,7 @@ func (p SourcePath) OverlayPath(ctx ModuleMissingDepsPathContext, path Path) Opt ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path) return OptionalPath{} } - dir := filepath.Join(p.config.srcDir, p.path, relDir) + dir := filepath.Join(p.srcDir, p.path, relDir) // Use Glob so that we are run again if the directory is added. if pathtools.IsGlob(dir) { ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir) @@ -1136,13 +1198,17 @@ func (p SourcePath) OverlayPath(ctx ModuleMissingDepsPathContext, path Path) Opt if len(paths) == 0 { return OptionalPath{} } - relPath := Rel(ctx, p.config.srcDir, paths[0]) + relPath := Rel(ctx, p.srcDir, paths[0]) return OptionalPathForPath(PathForSource(ctx, relPath)) } // OutputPath is a Path representing an intermediates file path rooted from the build directory type OutputPath struct { basePath + + // The soong build directory, i.e. Config.BuildDir() + buildDir string + fullPath string } @@ -1157,8 +1223,18 @@ func (p OutputPath) WithoutRel() OutputPath { return p } -func (p OutputPath) buildDir() string { - return p.config.buildDir +func (p OutputPath) getBuildDir() string { + return p.buildDir +} + +func (p OutputPath) RelativeToTop() Path { + return p.outputPathRelativeToTop() +} + +func (p OutputPath) outputPathRelativeToTop() OutputPath { + p.fullPath = StringPathRelativeToTop(p.buildDir, p.fullPath) + p.buildDir = OutSoongDir + return p } func (p OutputPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath { @@ -1174,6 +1250,11 @@ type toolDepPath struct { basePath } +func (t toolDepPath) RelativeToTop() Path { + ensureTestOnly() + return t +} + var _ Path = toolDepPath{} // pathForBuildToolDep returns a toolDepPath representing the given path string. @@ -1182,7 +1263,7 @@ var _ Path = toolDepPath{} // Only use this function to construct paths for dependencies of the build // tool invocation. func pathForBuildToolDep(ctx PathContext, path string) toolDepPath { - return toolDepPath{basePath{path, ctx.Config(), ""}} + return toolDepPath{basePath{path, ""}} } // PathForOutput joins the provided paths and returns an OutputPath that is @@ -1195,7 +1276,7 @@ func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath { } fullPath := filepath.Join(ctx.Config().buildDir, path) path = fullPath[len(fullPath)-len(path):] - return OutputPath{basePath{path, ctx.Config(), ""}, fullPath} + return OutputPath{basePath{path, ""}, ctx.Config().buildDir, fullPath} } // PathsForOutput returns Paths rooted from buildDir @@ -1351,7 +1432,13 @@ type ModuleOutPath struct { OutputPath } +func (p ModuleOutPath) RelativeToTop() Path { + p.OutputPath = p.outputPathRelativeToTop() + return p +} + var _ Path = ModuleOutPath{} +var _ WritablePath = ModuleOutPath{} func (p ModuleOutPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath { return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext)) @@ -1429,7 +1516,8 @@ func PathForBazelOut(ctx PathContext, paths ...string) BazelOutPath { reportPathError(ctx, err) } - outputPath := OutputPath{basePath{"", ctx.Config(), ""}, + outputPath := OutputPath{basePath{"", ""}, + ctx.Config().buildDir, ctx.Config().BazelContext.OutputBase()} return BazelOutPath{ @@ -1455,7 +1543,13 @@ type ModuleGenPath struct { ModuleOutPath } +func (p ModuleGenPath) RelativeToTop() Path { + p.OutputPath = p.outputPathRelativeToTop() + return p +} + var _ Path = ModuleGenPath{} +var _ WritablePath = ModuleGenPath{} var _ genPathProvider = ModuleGenPath{} var _ objPathProvider = ModuleGenPath{} @@ -1488,7 +1582,13 @@ type ModuleObjPath struct { ModuleOutPath } +func (p ModuleObjPath) RelativeToTop() Path { + p.OutputPath = p.outputPathRelativeToTop() + return p +} + var _ Path = ModuleObjPath{} +var _ WritablePath = ModuleObjPath{} // PathForModuleObj returns a Path representing the paths... under the module's // 'obj' directory. @@ -1506,7 +1606,13 @@ type ModuleResPath struct { ModuleOutPath } +func (p ModuleResPath) RelativeToTop() Path { + p.OutputPath = p.outputPathRelativeToTop() + return p +} + var _ Path = ModuleResPath{} +var _ WritablePath = ModuleResPath{} // PathForModuleRes returns a Path representing the paths... under the module's // 'res' directory. @@ -1523,6 +1629,9 @@ func PathForModuleRes(ctx ModuleOutPathContext, pathComponents ...string) Module type InstallPath struct { basePath + // The soong build directory, i.e. Config.BuildDir() + buildDir string + // partitionDir is the part of the InstallPath that is automatically determined according to the context. // For example, it is host/<os>-<arch> for host modules, and target/product/<device>/<partition> for device modules. partitionDir string @@ -1531,8 +1640,28 @@ type InstallPath struct { makePath bool } -func (p InstallPath) buildDir() string { - return p.config.buildDir +// Will panic if called from outside a test environment. +func ensureTestOnly() { + // Normal soong test environment + if InList("-test.short", os.Args) { + return + } + // IntelliJ test environment + if InList("-test.v", os.Args) { + return + } + + panic(fmt.Errorf("Not in test\n%s", strings.Join(os.Args, "\n"))) +} + +func (p InstallPath) RelativeToTop() Path { + ensureTestOnly() + p.buildDir = OutSoongDir + return p +} + +func (p InstallPath) getBuildDir() string { + return p.buildDir } func (p InstallPath) ReplaceExtension(ctx PathContext, ext string) OutputPath { @@ -1547,9 +1676,9 @@ func (p InstallPath) writablePath() {} func (p InstallPath) String() string { if p.makePath { // Make path starts with out/ instead of out/soong. - return filepath.Join(p.config.buildDir, "../", p.path) + return filepath.Join(p.buildDir, "../", p.path) } else { - return filepath.Join(p.config.buildDir, p.path) + return filepath.Join(p.buildDir, p.path) } } @@ -1558,9 +1687,9 @@ func (p InstallPath) String() string { // The ./soong is dropped if the install path is for Make. func (p InstallPath) PartitionDir() string { if p.makePath { - return filepath.Join(p.config.buildDir, "../", p.partitionDir) + return filepath.Join(p.buildDir, "../", p.partitionDir) } else { - return filepath.Join(p.config.buildDir, p.partitionDir) + return filepath.Join(p.buildDir, p.partitionDir) } } @@ -1643,7 +1772,8 @@ func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, } base := InstallPath{ - basePath: basePath{partionPath, ctx.Config(), ""}, + basePath: basePath{partionPath, ""}, + buildDir: ctx.Config().buildDir, partitionDir: partionPath, makePath: false, } @@ -1653,7 +1783,8 @@ func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath { base := InstallPath{ - basePath: basePath{prefix, ctx.Config(), ""}, + basePath: basePath{prefix, ""}, + buildDir: ctx.Config().buildDir, partitionDir: prefix, makePath: false, } @@ -1788,7 +1919,7 @@ func PathForPhony(ctx PathContext, phony string) WritablePath { if strings.ContainsAny(phony, "$/") { ReportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony) } - return PhonyPath{basePath{phony, ctx.Config(), ""}} + return PhonyPath{basePath{phony, ""}} } type PhonyPath struct { @@ -1797,8 +1928,16 @@ type PhonyPath struct { func (p PhonyPath) writablePath() {} -func (p PhonyPath) buildDir() string { - return p.config.buildDir +func (p PhonyPath) getBuildDir() string { + // A phone path cannot contain any / so cannot be relative to the build directory. + return "" +} + +func (p PhonyPath) RelativeToTop() Path { + ensureTestOnly() + // A phony path cannot contain any / so does not have a build directory so switching to a new + // build directory has no effect so just return this path. + return p } func (p PhonyPath) ReplaceExtension(ctx PathContext, ext string) OutputPath { @@ -1812,10 +1951,17 @@ type testPath struct { basePath } +func (p testPath) RelativeToTop() Path { + ensureTestOnly() + return p +} + func (p testPath) String() string { return p.path } +var _ Path = testPath{} + // PathForTesting returns a Path constructed from joining the elements of paths with '/'. It should only be used from // within tests. func PathForTesting(paths ...string) Path { diff --git a/android/testing.go b/android/testing.go index 1436f0b86..3f3f7690c 100644 --- a/android/testing.go +++ b/android/testing.go @@ -909,7 +909,7 @@ func NormalizePathForTesting(path Path) string { } p := path.String() if w, ok := path.(WritablePath); ok { - rel, err := filepath.Rel(w.buildDir(), p) + rel, err := filepath.Rel(w.getBuildDir(), p) if err != nil { panic(err) } @@ -935,19 +935,14 @@ func NormalizePathsForTesting(paths Paths) []string { // PathRelativeToTop returns a string representation of the path relative to a notional top // directory. // -// For a WritablePath it applies StringPathRelativeToTop to it, using the buildDir returned from the -// WritablePath's buildDir() method. For all other paths, i.e. source paths, that are already -// relative to the top it just returns their string representation. +// It return "<nil path>" if the supplied path is nil, otherwise it returns the result of calling +// Path.RelativeToTop to obtain a relative Path and then calling Path.String on that to get the +// string representation. func PathRelativeToTop(path Path) string { if path == nil { return "<nil path>" } - p := path.String() - if w, ok := path.(WritablePath); ok { - buildDir := w.buildDir() - return StringPathRelativeToTop(buildDir, p) - } - return p + return path.RelativeToTop().String() } // PathsRelativeToTop creates a slice of strings where each string is the result of applying @@ -964,23 +959,13 @@ func PathsRelativeToTop(paths Paths) []string { // StringPathRelativeToTop returns a string representation of the path relative to a notional top // directory. // -// A standard build has the following structure: -// ../top/ -// out/ - make install files go here. -// out/soong - this is the buildDir passed to NewTestConfig() -// ... - the source files -// -// This function converts a path so that it appears relative to the ../top/ directory, i.e. -// * Make install paths, which have the pattern "buildDir/../<path>" are converted into the top -// relative path "out/<path>" -// * Soong install paths and other writable paths, which have the pattern "buildDir/<path>" are -// converted into the top relative path "out/soong/<path>". -// * Source paths are already relative to the top. +// See Path.RelativeToTop for more details as to what `relative to top` means. // // This is provided for processing paths that have already been converted into a string, e.g. paths // in AndroidMkEntries structures. As a result it needs to be supplied the soong output dir against // which it can try and relativize paths. PathRelativeToTop must be used for process Path objects. func StringPathRelativeToTop(soongOutDir string, path string) string { + ensureTestOnly() // A relative path must be a source path so leave it as it is. if !filepath.IsAbs(path) { @@ -1833,12 +1833,6 @@ func (c *Module) deps(ctx DepsContext) Deps { if c.compiler != nil { deps = c.compiler.compilerDeps(ctx, deps) } - // Add the PGO dependency (the clang_rt.profile runtime library), which - // sometimes depends on symbols from libgcc, before libgcc gets added - // in linkerDeps(). - if c.pgo != nil { - deps = c.pgo.deps(ctx, deps) - } if c.linker != nil { deps = c.linker.linkerDeps(ctx, deps) } diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go index 59c042230..fce28c1ee 100644 --- a/cc/config/toolchain.go +++ b/cc/config/toolchain.go @@ -245,10 +245,6 @@ func ThreadSanitizerRuntimeLibrary(t Toolchain) string { return LibclangRuntimeLibrary(t, "tsan") } -func ProfileRuntimeLibrary(t Toolchain) string { - return LibclangRuntimeLibrary(t, "profile") -} - func ScudoRuntimeLibrary(t Toolchain) string { return LibclangRuntimeLibrary(t, "scudo") } @@ -22,7 +22,6 @@ import ( "github.com/google/blueprint/proptools" "android/soong/android" - "android/soong/cc/config" ) var ( @@ -271,14 +270,6 @@ func (pgo *pgo) begin(ctx BaseModuleContext) { } } -func (pgo *pgo) deps(ctx BaseModuleContext, deps Deps) Deps { - if pgo.Properties.ShouldProfileModule { - runtimeLibrary := config.ProfileRuntimeLibrary(ctx.toolchain()) - deps.LateStaticLibs = append(deps.LateStaticLibs, runtimeLibrary) - } - return deps -} - func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { if ctx.Host() { return flags diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 8873b4ef7..02f112074 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -33,6 +33,8 @@ type GlobalConfig struct { OnlyPreoptBootImageAndSystemServer bool // only preopt jars in the boot image or system server + PreoptWithUpdatableBcp bool // If updatable boot jars are included in dexpreopt or not. + UseArtImage bool // use the art image (use other boot class path dex files without image) HasSystemOther bool // store odex files that match PatternsOnSystemOther on the system_other partition diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go index 48014824b..c0ba5ca4e 100644 --- a/dexpreopt/testing.go +++ b/dexpreopt/testing.go @@ -117,3 +117,17 @@ func FixtureSetBootJars(bootJars ...string) android.FixturePreparer { dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList(bootJars) }) } + +// FixtureSetUpdatableBootJars sets the UpdatableBootJars property in the global config. +func FixtureSetUpdatableBootJars(bootJars ...string) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.UpdatableBootJars = android.CreateTestConfiguredJarList(bootJars) + }) +} + +// FixtureSetPreoptWithUpdatableBcp sets the PreoptWithUpdatableBcp property in the global config. +func FixtureSetPreoptWithUpdatableBcp(value bool) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.PreoptWithUpdatableBcp = value + }) +} diff --git a/java/app_test.go b/java/app_test.go index 252353364..825ad203a 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -26,6 +26,7 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/dexpreopt" "android/soong/genrule" ) @@ -2422,6 +2423,66 @@ func TestUsesLibraries(t *testing.T) { `#PCL[/system/framework/android.test.mock.jar] `) } +func TestDexpreoptBcp(t *testing.T) { + bp := ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + api_packages: ["foo"], + sdk_version: "current", + } + + java_sdk_library { + name: "bar", + srcs: ["a.java"], + api_packages: ["bar"], + permitted_packages: ["bar"], + sdk_version: "current", + } + + android_app { + name: "app", + srcs: ["a.java"], + sdk_version: "current", + } + ` + + testCases := []struct { + name string + with bool + expect string + }{ + { + name: "with updatable bcp", + with: true, + expect: "/system/framework/foo.jar:/system/framework/bar.jar", + }, + { + name: "without updatable bcp", + with: false, + expect: "/system/framework/foo.jar", + }, + } + + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("runtime-library", "foo", "bar"), + dexpreopt.FixtureSetBootJars("platform:foo"), + dexpreopt.FixtureSetUpdatableBootJars("platform:bar"), + dexpreopt.FixtureSetPreoptWithUpdatableBcp(test.with), + ).RunTestWithBp(t, bp) + + app := result.ModuleForTests("app", "android_common") + cmd := app.Rule("dexpreopt").RuleParams.Command + bcp := " -Xbootclasspath-locations:" + test.expect + " " // space at the end matters + android.AssertStringDoesContain(t, "dexpreopt app bcp", cmd, bcp) + }) + } +} + func TestCodelessApp(t *testing.T) { testCases := []struct { name string diff --git a/java/dexpreopt.go b/java/dexpreopt.go index a2961c29e..b4cf012af 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -160,14 +160,17 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) + + isSystemServerJar := inList(ctx.ModuleName(), global.SystemServerJars) + bootImage := defaultBootImageConfig(ctx) - dexFiles := bootImage.dexPathsDeps.Paths() - // The dex locations for all Android variants are identical. - dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps if global.UseArtImage { bootImage = artBootImageConfig(ctx) } + // System server jars are an exception: they are dexpreopted without updatable bootclasspath. + dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp && !isSystemServerJar) + targets := ctx.MultiTargets() if len(targets) == 0 { // assume this is a java library, dexpreopt for all arches for now @@ -176,7 +179,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr targets = append(targets, target) } } - if inList(ctx.ModuleName(), global.SystemServerJars) && !d.isSDKLibrary { + if isSystemServerJar && !d.isSDKLibrary { // If the module is not an SDK library and it's a system server jar, only preopt the primary arch. targets = targets[:1] } @@ -237,7 +240,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr DexPreoptImagesDeps: imagesDeps, DexPreoptImageLocations: imageLocations, - PreoptBootClassPathDexFiles: dexFiles, + PreoptBootClassPathDexFiles: dexFiles.Paths(), PreoptBootClassPathDexLocations: dexLocations, PreoptExtractedApk: false, diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 17499ee7d..7137f33ba 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -214,7 +214,7 @@ import ( var artApexNames = []string{ "com.android.art", "com.android.art.debug", - "com.android.art,testing", + "com.android.art.testing", "com.google.android.art", "com.google.android.art.debug", "com.google.android.art.testing", @@ -439,6 +439,8 @@ func (d *dexpreoptBootJars) GenerateSingletonBuildActions(ctx android.SingletonC // Create boot image for the ART apex (build artifacts are accessed via the global boot image config). d.otherImages = append(d.otherImages, buildBootImage(ctx, artBootImageConfig(ctx))) + copyUpdatableBootJars(ctx) + dumpOatRules(ctx, d.defaultBootImage) } @@ -630,6 +632,21 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI return image } +// Generate commands that will copy updatable boot jars to predefined paths in the global config. +func copyUpdatableBootJars(ctx android.SingletonContext) { + config := GetUpdatableBootConfig(ctx) + getBootJarFunc := func(module android.Module) (int, android.Path) { + index, jar, _ := getBootJar(ctx, config.modules, module, "configured in updatable boot jars ") + return index, jar + } + missingDeps := findAndCopyBootJars(ctx, config.modules, config.dexPaths, getBootJarFunc) + // Ignoring missing dependencies here. Ideally they should be added to the dexpreopt rule, but + // that is not possible as this rule is created after dexpreopt rules (it's in a singleton + // context, and they are in a module context). The true fix is to add dependencies from the + // dexpreopted modules on updatable boot jars and avoid this copying altogether. + _ = missingDeps +} + // Generate boot image build rules for a specific target. func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant, profile android.Path, missingDeps []string) android.WritablePaths { @@ -997,8 +1014,11 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { image := d.defaultBootImage if image != nil { ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String()) - ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " ")) - ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.getAnyAndroidVariant().dexLocationsDeps, " ")) + + global := dexpreopt.GetGlobalConfig(ctx) + dexPaths, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp) + ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(dexPaths.Strings(), " ")) + ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(dexLocations, " ")) var imageNames []string // TODO: the primary ART boot image should not be exposed to Make, as it is installed in a diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index 282e9364e..64b265640 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -176,6 +176,57 @@ func defaultBootclasspath(ctx android.PathContext) []string { }) } +// Updatable boot config allows to access build/install paths of updatable boot jars without going +// through the usual trouble of registering dependencies on those modules and extracting build paths +// from those dependencies. +type updatableBootConfig struct { + // A list of updatable boot jars. + modules android.ConfiguredJarList + + // A list of predefined build paths to updatable boot jars. They are configured very early, + // before the modules for these jars are processed and the actual paths are generated, and + // later on a singleton adds commands to copy actual jars to the predefined paths. + dexPaths android.WritablePaths + + // A list of dex locations (a.k.a. on-device paths) to the boot jars. + dexLocations []string +} + +var updatableBootConfigKey = android.NewOnceKey("updatableBootConfig") + +// Returns updatable boot config. +func GetUpdatableBootConfig(ctx android.PathContext) updatableBootConfig { + return ctx.Config().Once(updatableBootConfigKey, func() interface{} { + updatableBootJars := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars + + dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "updatable_bootjars") + dexPaths := updatableBootJars.BuildPaths(ctx, dir) + + dexLocations := updatableBootJars.DevicePaths(ctx.Config(), android.Android) + + return updatableBootConfig{updatableBootJars, dexPaths, dexLocations} + }).(updatableBootConfig) +} + +// Returns a list of paths and a list of locations for the boot jars used in dexpreopt (to be +// passed in -Xbootclasspath and -Xbootclasspath-locations arguments for dex2oat). +func bcpForDexpreopt(ctx android.PathContext, withUpdatable bool) (android.WritablePaths, []string) { + // Non-updatable boot jars (they are used both in the boot image and in dexpreopt). + bootImage := defaultBootImageConfig(ctx) + dexPaths := bootImage.dexPathsDeps + // The dex locations for all Android variants are identical. + dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps + + if withUpdatable { + // Updatable boot jars (they are used only in dexpreopt, but not in the boot image). + updBootConfig := GetUpdatableBootConfig(ctx) + dexPaths = append(dexPaths, updBootConfig.dexPaths...) + dexLocations = append(dexLocations, updBootConfig.dexLocations...) + } + + return dexPaths, dexLocations +} + var defaultBootclasspathKey = android.NewOnceKey("defaultBootclasspath") var copyOf = android.CopyOf diff --git a/java/java_test.go b/java/java_test.go index 9924be7bf..13b3e2a90 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -1429,7 +1429,7 @@ func TestDroiddoc(t *testing.T) { barStubsOutput := barStubsOutputs[0] barDoc := ctx.ModuleForTests("bar-doc", "android_common") javaDoc := barDoc.Rule("javadoc").RelativeToTop() - if g, w := javaDoc.Implicits.Strings(), barStubsOutput.String(); !inList(w, g) { + if g, w := android.PathsRelativeToTop(javaDoc.Implicits), android.PathRelativeToTop(barStubsOutput); !inList(w, g) { t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g) } @@ -1439,7 +1439,7 @@ func TestDroiddoc(t *testing.T) { } aidl := barDoc.Rule("aidl") - if g, w := javaDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) { + if g, w := android.PathsRelativeToTop(javaDoc.Implicits), android.PathRelativeToTop(aidl.Output); !inList(w, g) { t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g) } |